MyBatis
MyBatis
JDBC执行步骤
JDBC(Java Data Base Connectivity),Java 语言访问数据库的标准 API
- 注册驱动
- 建立连接
- 创建SQL
- 执行SQL
- 封装结果集
- 释放资源
1 | |
mybatis简化 了JDBC 的重复劳动
SpringBoot中使用MyBatis
导入依赖
1 | |
准备数据库信息
1 | |
添加配置信息
在resource/application.yml中添加
1 | |
添加三层架构
实体类entity
1 | |
mapper及其映射文件
MybatisTestMapper.xml放在了resource下和MybatisTestMapper.java一样名字的文件夹下,方便管理
1 | |
1 | |
Service层
接口
1 | |
实现类
1 | |
Controller层
1 | |
启动类
1 | |
测试
浏览器访问
http://localhost:8080/getMybatisInfo/1api测试工具访问
localhost:8080/saveMybatisInfo,body中带上json1
2
3
4
5{
"name": "shone",
"phone": "123456789",
"email": "46465456@qq.com"
}
相关配置
数据源
1 | |
mybatis基础配置
1 | |
- 一级缓存(默认):SqlSession 级别,每个 SqlSession 独立缓存,SqlSession 关闭就失效。
- 二级缓存:Mapper 级别,跨 SqlSession 缓存,多个 SqlSession 都可以共享缓存数据,只对同一个Mapper生效,不适合频繁更新的表。
- 懒加载:查询的一个对象里面还有嵌套另一个对象时,先不查出来,等到
get的时候再查
相关注解
@Mapper
作用:标记一个接口是 MyBatis 的 Mapper,Spring 扫描后会自动生成代理对象。
使用场景:如果不使用 @MapperScan,就需要在每个 Mapper 接口上写 @Mapper。
1 | |
@MapperScan
作用:扫描指定包下的 Mapper 接口,自动注册为 Spring Bean。
使用场景:推荐放在 Spring Boot 启动类上,避免每个接口都写 @Mapper。
1 | |
@Param
作用:指定方法参数的名字,在 SQL 中引用
1 | |
在实体类上使用的lombok注解
构造、getter/setter等自己写比较好,用lombok注解可能配合其他框架会出问题
@Getter/ @Setter
- 作用:自动生成 getter 和 setter 方法。
@ToString
- 作用:自动生成
toString()方法。
@EqualsAndHashCode
- 作用:生成
equals()和hashCode()方法。
@Data
- 作用:相当于
@Getter+@Setter+@ToString+@EqualsAndHashCode+@RequiredArgsConstructor的组合注解。
@NoArgsConstructor
- 作用:生成无参构造函数。
@AllArgsConstructor
- 作用:生成全参构造函数(所有字段)。
XML映射文件的语法
顶层结构
namespace=Mapper接口的全限定类名
1 | |
操作标签
| 标签 | 说明 | 示例 |
|---|---|---|
<select> |
查询语句 | <select id="getUserById" resultType="User">SELECT * FROM user WHERE id=#{id}</select> |
<insert> |
插入语句 | <insert id="insertUser" parameterType="User">INSERT INTO user(name, age) VALUES(#{name}, #{age})</insert> |
<update> |
更新语句 | <update id="updateUser" parameterType="User">UPDATE user SET name=#{name} WHERE id=#{id}</update> |
<delete> |
删除语句 | <delete id="deleteUserById" parameterType="long">DELETE FROM user WHERE id=#{id}</delete> |
结果映射标签
适合实体类和表的字段名不一致的情况
1 | |
占位符
${}:字符串拼接,直接替换,不安全,一般用于表名、列名#{}:参数绑定,防止 SQL 注入(PreparedStatement)
动态sql标签
| 标签 | 作用 | 示例 |
|---|---|---|
<if> |
条件判断 | <if test="age != null">AND age = #{age}</if> |
<choose> |
类似 if-else | <choose><when test="age != null">AND age = #{age}</when><otherwise>AND age > 0</otherwise></choose> |
<trim> |
去掉多余前后关键字 | `<trim prefix=”WHERE” prefixOverrides=”AND |
<where> |
自动处理 WHERE 和多余的 AND/OR | <where><if test="name != null">AND name = #{name}</if></where> |
<set> |
自动处理 UPDATE SET 多余逗号 | <set><if test="name != null">name=#{name},</if></set> |
<foreach> |
遍历集合或数组 | <foreach collection="ids" item="id" open="(" separator="," close=")">#{id}</foreach> |
SQL 语句复用
1 | |
MyBatis Plus
代码生成器
使用方式
导入坐标
注意mybatis-plus-generator的版本必须为3.5.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!--MybatisPlus、MybatisPlus生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>编写配置
1
2
3
4
5
6
7
8
9
10
11
12server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
mybatis:
mapper-locations:
- classpath:mapper/*.xml
- classpath*:com/**/mapper/*.xml编写代码,执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113package com.xw.mallLearning.generator;
/**
* 用于生产MBG的代码
*/
public class Generator {
// 基础信息配置
private static final String URL = "jdbc:mysql://localhost:3306/mall?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai";
private static final String USERNAME = "root";
private static final String PASSWORD = "123456";
private static final String PARENT_PACKAGE_NAME = "com.xw.mallLearning.generator"; // 包名
private static final String PROJECT_ROOT_PATH = System.getProperty("user.dir");
private static final String PROJECT_NAME = "mall-learning"; // 当前项目名称
private static final String MODULE_NAME = "mbg"; // 模块名称, 代码会生成在generator/MODULE_NAME下
/**
* 执行此处
*/
public static void main(String[] args) {
simpleGenerator();
}
protected static void simpleGenerator() {
// 添加需要自动生成代码的表名, 为空则生成所有表对应代码
List<String> tables = new ArrayList<>();
tables.add("pms_brand");
// 包路径
String packagePath = PROJECT_ROOT_PATH + "/" + PROJECT_NAME + "/src/main/java";
// XML文件的路径
String mapperXmlPath = PROJECT_ROOT_PATH + "/" + PROJECT_NAME + "/src/main/resources/mapper";
// 开始执行代码生成
FastAutoGenerator.create(URL, USERNAME, PASSWORD)
// 1. 全局配置
.globalConfig(builder -> builder
// 作者名称
.author("xw")
// 开启覆盖已生成的文件。注释掉则关闭覆盖。
.fileOverride()
// 禁止打开输出目录。注释掉则生成完毕后,自动打开生成的文件目录。
.disableOpenDir()
// 指定输出目录。如果指定,Windows生成至D盘根目录下,Linux or MAC 生成至 /tmp 目录下。
.outputDir(packagePath)
// 开启swagger2.注释掉则默认关闭。
// .enableSwagger()
// 指定时间策略。
.dateType(DateType.TIME_PACK)
// 注释时间策略。
.commentDate("yyyy-MM-dd")
)
// 2. 包配置
.packageConfig(builder -> builder
// 设置父表名
.parent(PARENT_PACKAGE_NAME)
.moduleName(MODULE_NAME)
.entity("entity")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.mapper("mapper")
.xml("mapper")
// mapper.xml 文件的路径。单模块下,其他文件路径默认即可。
.pathInfo(Collections.singletonMap(OutputFile.mapperXml, mapperXmlPath))
)
// 3. 策略配置
.strategyConfig(builder -> builder.addInclude(tables)
// 阶段1:Entity实体类策略配置
.entityBuilder()
// 开启生成实体时生成字段注解。
// 会在实体类的属性前,添加[@TableField("nickname")]
.enableTableFieldAnnotation()
// 逻辑删除字段名(数据库)。
//.logicDeleteColumnName("is_delete")
// 逻辑删除属性名(实体)。
// 会在实体类的该字段属性前加注解[@TableLogic]
//.logicDeletePropertyName("isDelete")
// 会在实体类的该字段上追加注解[@TableField(value = "create_time", fill = FieldFill.INSERT)]
.addTableFills(new Column("create_time", FieldFill.INSERT))
// 会在实体类的该字段上追加注解[@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)]
.addTableFills(new Column("update_time", FieldFill.INSERT_UPDATE))
// 阶段2:Mapper策略配置
.mapperBuilder()
// 开启 @Mapper 注解。
// 会在mapper接口上添加注解[@Mapper]
.enableMapperAnnotation()
// 启用 BaseResultMap 生成。
// 会在mapper.xml文件生成[通用查询映射结果]配置。
.enableBaseResultMap()
// 启用 BaseColumnList。
// 会在mapper.xml文件生成[通用查询结果列 ]配置
.enableBaseColumnList()
// 阶段4:Controller策略配置
.controllerBuilder()
// 会在控制类中加[@RestController]注解。
.enableRestStyle()
// 开启驼峰转连字符
.enableHyphenStyle()
.build()
)
// 4. 模板引擎配置,默认 Velocity 可选模板引擎 Beetl 或 Freemarker
//.templateEngine(new BeetlTemplateEngine())
.templateEngine(new FreemarkerTemplateEngine())
// 5. 执行
.execute();
}
}
分页插件
在mp配置类中添加分页插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Configuration
public class MpConfig {
/**
* 分页插件
* @return
*/
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}测试selectPage
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19@Test
public void testSelectPage() {
Page<User> page = new Page<>(1, 3);
Page<User> userPage = mapper.selectPage(page, null);
//返回对象得到分页所有数据
long pages = userPage.getPages(); //总页数
long current = userPage.getCurrent(); //当前页
List<User> records = userPage.getRecords(); //查询数据集合
long total = userPage.getTotal(); //总记录数
boolean hasNext = userPage.hasNext(); //下一页
boolean hasPrevious = userPage.hasPrevious(); //上一页
System.out.println(pages);
System.out.println(current);
System.out.println(records);
System.out.println(total);
System.out.println(hasNext);
System.out.println(hasPrevious);
}
公共字段自动填充
- 在需要自动填充的字段上添加
@TableField(fill)注解
参数:
fill
| 可填入的值 | 说明 |
|---|---|
| FieldFill.INSERT | 插入表时填充 |
| FieldFill.UPDATE | 更新时填充 |
| FieldFill.INSERT_UPDATE | 更新和插入表时填充 |
1 | |
- 实现
MetaObjectHandler接口, 重写insertFill()和updateFill()方法
1 | |
乐观锁
在mp配置类中添加乐观锁插件
1
2
3
4
5
6
7
8
9
10
11
12@Configuration
public class MpConfig {
/**
* 乐观锁插件
* @return
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}给类上添加
version属性1
2
3@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;插入时自动填充
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}每次要修改时先查询出要修改的数据,修改后再放回数据库,version值会自动加一
逻辑删除
删除数据只是逻辑上删除,数据库中还能查到
使用场景:
可以进行数据恢复
有关联数据,不便删除
表中添加
deleted字段,类型为boolean默认值为false修改实体类,添加
deleted字段1
2@TableLogic
private Integer deleted;配置(下面是默认配置,可配可不配)
1
2
3# 逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0测试