1.MyBatis是什么
持久层框架 【也是一个ORM框架 对象关系映射】
是一个优秀的ORM持久层框架
特点:灵活
支持自定义SQL、存储过程以及高级映射。MyBatis去除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO为数据库中的记录。
回顾JDBC操作步骤
- 创建数据库连接池 DataSource
- 通过 DataSource 获取数据库连接 Connection
- 编写要执⾏带 ? 占位符的 SQL 语句
- 通过 Connection 及 SQL 创建操作命令对象 Statement
- 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
- 使⽤ Statement 执⾏ SQL 语句
- 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
- 处理结果集
- 释放资源
对于 JDBC 来说,整个操作⾮常的繁琐,我们不但要拼接每⼀个参数,⽽且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关闭连接等,⽽所有的这些操作步骤都需要在每个⽅法中重复书写。
2.MyBatis入门
MyBatis分为两部分:
- 配置 MyBatis 开发环境
- 使用 MyBatis 模式和语法操作数据库
创建 MyBatis 项目
-
创建数据库和数据表
-- 创建数据库 drop database if exists mycnblog; create database mycnblog DEFAULT CHARACTER SET utf8mb4; -- 使⽤数据数据 use mycnblog; -- 创建表[⽤户表] drop table if exists userinfo; create table userinfo( id int primary key auto_increment, username varchar(100) not null, password varchar(32) not null, photo varchar(500) default '', createtime datetime default now(), updatetime datetime default now(), `state` int default 1 ) default charset 'utf8mb4'; -- 创建⽂章表 drop table if exists articleinfo; create table articleinfo( id int primary key auto_increment, title varchar(100) not null, content text not null, createtime datetime default now(), updatetime datetime default now(), uid int not null, rcount int not null default 1, `state` int default 1 )default charset 'utf8mb4'; -- 创建视频表 drop table if exists videoinfo; create table videoinfo( vid int primary key, `title` varchar(250), `url` varchar(1000), createtime datetime default now(), updatetime datetime default now(), uid int )default charset 'utf8mb4'; -- 添加⼀个⽤户信息 INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES (1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1) ; -- ⽂章添加测试数据 insert into articleinfo(title,content,uid) values('Java','Java正⽂',1); -- 添加视频 insert into videoinfo(vid,title,url,uid) values(1,'java title','http://ww w.baidu.com',1);
-
一、添加 MyBatis 相关依赖
-
新项目添加 MyBatis 依赖
- 老项目添加 MyBatis 依赖
-
-
二、配置数据库连接字符串和 MyBatis (保存的 XML 的目录)
如果使⽤ mysql-connector-java 是 5.x 之前的使⽤的是“com.mysql.jdbc.Driver”,如果是⼤于 5.x
使⽤的是“com.mysql.cj.jdbc.Driver”。-
数据库连接
-
mybatis保存的xml路径
-
-
三、使用 MyBatis 的操作模式操作数据库
MyBatis 模式只包含两个部分的东西:
-
接口(定义方法的声明)
-
xml 实现接口中的方法
生成数据库可以执行sql,并且执行sql将结果映射到程序的对象中。
-
MyBatis实现查询:
代码结构:
MyBatis 增删改查
-
在 mapper(interface)里面添加代码声明
package com.example.mybatis_2023.mapper; import com.example.mybatis_2023.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; /** * @author SunYuHang * @date 2023-02-01 12:51 * @ClassName : UserMapper //类名 */ @Mapper // mybatis interface public interface UserMapper { //根据用户id查询用户 public UserInfo getUserById(@Param("id") Integer id);// @Param在xml中id使用id获取 // 修改方法 【根据id修改名称】 public int update(@Param("id") Integer id,@Param("username") String username); //删除方法 public int del(@Param("id") Integer id); // 添加用户,返回受影响的行数 public int add(UserInfo userInfo); //添加用户,返回受影响的行数和用户自增id public int addGetId(UserInfo userInfo); }
-
在 xml 中添加相关标签和sql语句
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace 要设置是实现接口的具体包名加类名 --> <mapper namespace="com.example.mybatis_2023.mapper.UserMapper"> <!-- 根据 id 查询用户 --> <select id="getUserById" resultType="com.example.mybatis_2023.model.UserInfo"> select * from userinfo where id=#{id} </select> <!-- 根据用户 id 修改用户名称 --> <update id="update"> update userinfo set username=#{username} where id=#{id} </update> <!-- 根据用户 id 删除用户 --> <delete id="del"> delete from mycnblog.userinfo where id=#{id} </delete> <!-- 添加用户,返回受影响的行数 --> <insert id="add"> insert into mycnblog.userinfo (username, password) values (#{username},#{password}) </insert> <!-- 添加用户,返回受影响的行数和用户自增id--> <insert id="addGetId" useGeneratedKeys="true" keyProperty="id" keyColumn="id"> insert into mycnblog.userinfo (username, password) values (#{username},#{password}) </insert> </mapper>
-
在 UserMapperTest 进行单元测试
package com.example.mybatis_2023.mapper; import com.example.mybatis_2023.model.UserInfo; import org.apache.ibatis.logging.stdout.StdOutImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; @SpringBootTest //表示当前单元测试运行在 spring boot 环境中 class UserMapperTest { @Autowired // 属性注入 private UserMapper userMapper; @Test void getUserById() { UserInfo userInfo = userMapper.getUserById(1); Assertions.assertNotNull(userInfo); } @Test @Transactional //事务 事务回滚 void update() { int result = userMapper.update(2,"zmy"); Assertions.assertEquals(1,result); } @Test void del() { int result = userMapper.del(2); System.out.println("受影响的行数:"+result); Assertions.assertEquals(1,result); } @Test void add() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("孙宇航"); userInfo.setPassword("123"); int result = userMapper.add(userInfo); System.out.println("受影响的行数:"+ result); Assertions.assertEquals(1,result); } @Test @Transactional void addGetId() { UserInfo userInfo = new UserInfo(); userInfo.setUsername("孙"); userInfo.setPassword("123"); System.out.println("添加之前 user id:"+userInfo.getId()); int result = userMapper.addGetId(userInfo); System.out.println("受影响的行数:"+ result); System.out.println("添加之后 user id:"+userInfo.getId()); Assertions.assertEquals(1,result); } }
注意: ${} 和 #{} 的区别
-
使用 #{} 得到的JDBC代码:【针对String类型的参数】
==> Preparing: select * from userinfo where id=? //【预查询】预处理 ==> Parameters: 1(Integer)
-
使用 ${} 得到的JDBC代码:【针对int类型的参数】
==> Preparing: select * from userinfo where id=1 //【即时查询】即时处理
==> Parameters:
-
定义不同:
#{} 预编译处理
${} 字符直接替换
-
使用不同:
#{} 适用于所有类型的参数匹配
${} 只适用数值类型
-
安全性不同
#{} 性能高,并且没有安全问题
存在 S Q L 注入的问题【传递 S Q L 关键字或 S Q L 命令只能使用 {} 存在 SQL 注入的问题 【传递SQL关键字或SQL命令只能使用 存在SQL注入的问题【传递SQL关键字或SQL命令只能使用{}】{一定要在业务代码中对传递的值进行安全校验。}
MyBatis一对一查询【一个文章对应一个作者信息】
<!-- 一对一映射属性 -->
<association property="userInfo" resultMap="com.example.mybatis_2023.mapper.UserMapper.BaseMap"
columnPrefix="u_">
</association>
MyBatis一对多查询【一个用户多篇文章】
<!-- 一对多映射属性 -->
<collection property="username" resultMap="com.example.mybatis_2023.mapper.ArticleMapper.BaseMap"
columnPrefix="a_">
</collection>