什么是MyBatis
MyBatis是⼀款优秀的持久层框架,⽤于简化JDBC的开发.MyBatis是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库⼯具.
MyBatis入门
准备工作
创建工程
新建Spring Boot项目,并导⼊mybatis的起步依赖和mysql的驱动包.

数据准备
创建用户表,并创建对应的实体类User.
sql
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (
`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
`username` VARCHAR ( 127 ) NOT NULL,
`password` VARCHAR ( 127 ) NOT NULL,
`age` TINYINT ( 4 ) NOT NULL,
`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',
`phone` VARCHAR ( 15 ) DEFAULT NULL,
`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
`create_time` DATETIME DEFAULT now(),
`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
-- 添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
java
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
private Integer deleteFlag;
private Date createTime;
private Date updateTime;
}
配置数据库链接字符串
Mybatis中要连接数据库,需要数据库相关参数配置,在项目的配置文件中添加这些配置.
java
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456
编写持久层代码
在项⽬中,创建持久层接UserInfoMapper.
java
@Mapper
public interface UserInfoMapper {
@Select("select * from userinfo")
List<UserInfo> getUserInfoAll();
}
单元测试
在test目录下对接口进行测试
java
@SpringBootTest
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void getUserInfoAll() {
List<UserInfo> userInfos = userInfoMapper.getUserInfoAll();
for (UserInfo userInfo : userInfos) {
System.out.println(userInfo);
}
}
}

允许结果与数据库信息相符,接口与链接均正常.
MyBatis基础操作
打印日志
在MyBatis中,可以通过打印日志看到sql语句的执行,执行过程中传递的参数以及执行的结果.在配置文件中添加以下配置即可.
java
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

日志中包含多个信息:
红框中为执行的sql语句.
蓝框为传递的参数及其类型.
橙框为执行的结果.
传递参数
在操作数据库的应用中,经常需要指定一些参数来进行精准的操作.如果这些参数直接写在sql上,那么代码就会变得很繁琐.
解决⽅案:在⽅法中添加⼀个参数(id),将⽅法中的参数,传给sql语句.在sql语句中使用#{}来获取到方法中提供的参数.
java
//查询代码:
@Select("select * from userinfo where id = #{id}")
List<UserInfo> getUserInfoById(Integer id);
//测试代码:
@Test
void getUserInfoById() {
List<UserInfo> userInfos = userInfoMapper.getUserInfoById(2);
for (UserInfo userInfo : userInfos) {
System.out.println(userInfo);
}
}

从日志中观察到,sql语句中的id=后面为"?",是JDBC中所使用的占位符,参数列表中传递了Integer类型的值为2参数,查询的结果也为id=2,可见传递的参数正常到达数据库中.
也可以使用@Param设置别名,如果使⽤@Param设置别名,#{}⾥⾯的属性名必须和@Param 设置的⼀样.
java
//将id设置为di
@Select("select * from userinfo where id = #{di}")
List<UserInfo> getUserInfoByIdParam(@Param("di") Integer id);
@Test
void getUserInfoByIdParam() {
List<UserInfo> userInfos = userInfoMapper.getUserInfoByIdParam(2);
for (UserInfo userInfo : userInfos) {
System.out.println(userInfo);
}
}

执行结果正常.
Insert
插入的sql语句使用关键字Insert,在MyBatis中使用注解@Insert标识插入操作:
java
@Insert("insert into userinfo(name, password, age, gender) " +
"values (#{username},#{password},#{age},#{gender})")
//从对象中解析所需的参数
Integer insertUserInfo(UserInfo userInfo);
返回值类型为Integer,表示插入影响到了几行.
java
@Test
void insertUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("qianqi");
userInfo.setPassword("123456");
userInfo.setAge(19);
userInfo.setGender(0);
//直接传递对象
int n = userInfoMapper.insertUserInfo(userInfo);
System.out.println("插入影响到了"+n+"行");
}

返回主键:
在插入成功后,我们有时需要获得新插入的自增主键,如上面的id,如果想要拿到⾃增id,需要在Mapper接⼝的⽅法上添加⼀个Options的注解.将Options注解的useGeneratedKeys设置为true,将keyProperty设置为想要获得的主键名,如id.再使用对象的getId来获取到自增主键id.
java
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into userinfo(username, password, age, gender) " +
"values (#{username},#{password},#{age},#{gender})")
Integer insertUserInfo(UserInfo userInfo);
@Test
void insertUserInfo() {
UserInfo userInfo = new UserInfo();
userInfo.setUsername("qianqi");
userInfo.setPassword("123456");
userInfo.setAge(19);
userInfo.setGender(0);
int n = userInfoMapper.insertUserInfo(userInfo);
System.out.println("插入影响到了"+n+"行,数据id:"+userInfo.getId());
}

Delete
删除的使用方式与插入类似,将注释改为@Delete即可.
java
@Delete("delete from userinfo where id = #{id}")
Integer deleteUserInfo(Integer id);
@Test
void deleteUserInfo() {
int n = userInfoMapper.deleteUserInfo(7);
System.out.println("删除影响到了"+n+"行");
}



执行程序并刷新数据库,发现删除成功.
Update
修改的操作与之前类似,捡修饰符修改为@Update即可.
java
@Update("Update userinfo set age = 114514 where id = #{id}")
Integer updateUserInfo(Integer id);
@Test
void updateUserInfo() {
int n = userInfoMapper.updateUserInfo(6);
System.out.println("修改影响到了"+n+"行");
}



执行程序,观察数据库,发现结果正确.
Select
在上⾯查询时发现,有⼏个字段是没有赋值的,只有Java对象属性和数据库字段⼀模⼀样时,才会进⾏赋值.
SQL语句中,查询了delete_flag,create_time,update_time,但是这⼏个属性却没有给deleteFlag,createTime,updateTime赋值.
当⾃动映射查询结果时,MyBatis会获取结果中返回的列名并在Java类中查找相同名字的属性,忽略大小写.然而在数据库中的命名规范与Java的命名规范是不相同的,想要双方命名一致不可寻,我们只能另寻他法.
起别名
在SQL语句中,给列名起别名,保持别名和实体类属性名⼀样.
java
@Select("select id, username, password, age, gender, phone, " +
"delete_flag as deleteFlag,create_time as createTime," +
" update_time as updateTime from userinfo")
public List<UserInfo> getUserInfoAllParam();
@Test
void getUserInfoAllParam() {
List<UserInfo> userInfos = userInfoMapper.getUserInfoAllParam();
for (UserInfo userInfo : userInfos) {
System.out.println(userInfo);
}
}

在sql语句中起别名后,MyBatis就可以识别到返回的列名于Java类的属性名一直,从而进行赋值.
结果映射
使用@Results关键字对返回的结果进行映射,也就是将列名于Java属性名"绑定"起来.示例:@Result(column = "delete_flag",property = "deleteFlag"),在使用多个映射时,需要将这些映射语句装载到同一个@Result中:
java
@Select("select * from userinfo")
@Results({
@Result(column = "delete_flag",property = "deleteFlag"),
@Result(column = "create_time",property = "createTime"),
@Result(column = "update_time",property = "updateTime")
})
List<UserInfo> getUserInfoAll2();
@Test
void getUserInfoAll2() {
List<UserInfo> userInfos = userInfoMapper.getUserInfoAll2();
for (UserInfo userInfo : userInfos) {
System.out.println(userInfo);
}
}

开启驼峰命名
通常数据库列使⽤蛇形命名法进⾏命名(下划线分割各个单词),⽽Java属性⼀般遵循驼峰命名法约定.为了在这两种命名⽅式之间启⽤⾃动映射,需要将配置文件中的mapUnderscoreToCamelCase设置为true即可.名称转换实例:abc_def -> abcDef.
java
#开启驼峰转换
mybatis.configuration.map-underscore-to-camel-case=true
再次运行一开始的查询代码:
java
@Select("select * from userinfo")
List<UserInfo> getUserInfoAll();

正确的将数据库中的下划线命名转换为Java中的驼峰命名并赋值.