MyBatis-Plus笔记
Mybatis-Plus笔记
三更草堂老师
1.概述:
- MybatisPlus:是一款Mybatis增强工具,用于简化开发,提高效率。它在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
- 官网:https://mp.baomidou.com/
2.快速入门:
准备工作:
准备数据:
1
2
3
4
5
6
7
8
9
10
11CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_name` varchar(20) NOT NULL COMMENT '用户名',
`password` varchar(20) NOT NULL COMMENT '密码',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`address` varchar(100) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`user_name`,`password`,`name`,`age`,`address`) values (1,'ruiwen','123','瑞文',12,'山东'),(2,'gailun','1332','盖伦',13,'平顶山'),(3,'timu','123','提姆',22,'蘑菇石'),(4,'daji','1222','妲己',221,'狐山');
创建springboot工程
添加依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>创建启动类:
1
2
3
4
5
6
7
public class SGApplication {
public static void main(String[] args) {
SpringApplication.run(SGApplication.class);
}
}创建实体类:
1
2
3
4
5
6
7
8
9
10
11
public class User {
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private String address;
}
使用MybatisPlus
添加依赖:
1
2
3
4
5
6
7
8
9<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>配置数据库信息:
1
2
3
4
5
6spring:
datasource:
url: jdbc:mysql://localhost:3306/mp_db?characterEncoding=utf-8&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver创建Mapper接口:创建Mapper接口继承BaseMapper接口
1
2public interface UserMapper extends BaseMapper<User> {
}BaseMapper接口中已经提供了很多常用方法。所以我们只需要直接从容器中获取Mapper就可以进行操作了,不需要自己去编写Sql语句。
配置Mapper扫描:在启动类上配置我们的Mapper在哪个包。
1
2
3
4
5
6
7
8
public class SGApplication {
public static void main(String[] args) {
SpringApplication.run(SGApplication.class,args);
}
}获取Mapper进行测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MPTest {
private UserMapper userMapper;
public void testQueryList(){
System.out.println(userMapper.selectList(null));
}
}
3.常用设置:
- 默认情况下MP操作的表名就是实体类的类名,但是如果表名和类名不一致就需要我们自己设置映射规则。
3.1设置表映射规则
单独设置:可以在实体类的类名上加上@TableName注解进行标识。
例如:如果表名是tb_user,而实体类名是User则可以使用以下写法。
1
2
3
4
public class User {
//....
}
全局设置:全局表名设置前缀,一般一个项目表名的前缀都是统一风格的,这个时候如果一个一个在实体类上设置注解就太麻烦了。我们可以通过配置来设置全局的表名前缀。
例如:如果一个项目中所有的表名相比于类名都是多了个前缀:
tb_
。这可以使用如下方式配置。1
2
3
4
5mybatis-plus:
global-config:
db-config:
#表名前缀
table-prefix: tb_
3.2设置主键生成策略
测试代码:
1
2
3
4
5
6
7
8
public void testInsert(){
User user = new User();
user.setUserName("三更草堂222");
user.setPassword("7777");
int r = userMapper.insert(user);
System.out.println(r);
}
结果会是用户id是由算法生成的一长串数字。
单独设置:
- 默认情况下使用MP插入数据时,如果在我们没有设置主键生成策略的情况下默认的策略是基于雪花算法的自增id。
- 如果我们需要使用别的策略可以在定义实体类时,在代表主键的字段上加上
@TableId
注解,使用其type
属性指定主键生成策略。 - 例如:我们要设置主键自动增长则可以设置如下:
1
2
3
4
5
6
7
8
9
public class User {
private Long id;
//.....
}全部主键策略定义在了枚举类
IdType
中,IdType
有如下的取值:AUTO
数据库ID自增,依赖于数据库。该类型请确保数据库设置了 ID自增 否则无效
NONE
未设置主键类型。若在代码中没有手动设置主键,则会根据主键的全局策略自动生成(默认的主键全局策略是基于雪花算法的自增ID)
INPUT
需要手动设置主键,若不设置。插入操作生成SQL语句时,主键这一列的值会是
null
。ASSIGN_ID
当没有手动设置主键,即实体类中的主键属性为空时,才会自动填充,使用雪花算法
ASSIGN_UUID
当实体类的主键属性为空时,才会自动填充,使用UUID
全局设置:
1
2
3
4
5mybatis-plus:
global-config:
db-config:
# id生成策略 auto为数据库自增
id-type: auto
3.3设置字段映射关系
默认情况下MP会开启字段名列名的驼峰映射, 即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射 。如果需要关闭我们可以使用如下配置进行关闭。
1
2
3
4mybatis-plus:
configuration:
#是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
map-underscore-to-camel-case: false有些时候自动映射不过去:
- 默认情况下MP会根据实体类的属性名去映射表的列名。 如果数据库的列表和实体类的属性名不一致了我们可以使用
@TableField
注解的value
属性去设置映射关系。 - 例如:如果表中一个列名叫 address而 实体类中的属性名为addressStr则可以使用如下方式进行配置。
1
2
private String addressStr;- 默认情况下MP会根据实体类的属性名去映射表的列名。 如果数据库的列表和实体类的属性名不一致了我们可以使用
3.4日志
如果需要打印MP操作对应的SQL语句等,可以配置日志输出。配置方式如下:
1
2
3
4mybatis-plus:
configuration:
# 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4.基本使用(CRUD)
4.1插入数据:
- 我们可以使用insert方法来实现数据的插入,示例:
1 |
|
4.2删除操作:
- 我们可以使用deleteXXX方法来实现数据的删除,示例:
1 |
|
4.3 更新操作:
- 我们可以使用updateXXX方法来实现数据的删除,示例:
1 |
|
4.4查询操作:
- 之前快速入门那个示例就是
5.条件构造器Wrapper(重点)
5.1 概述
- 我们在实际操作数据库的时候会涉及到很多的条件。所以MP为我们提供了一个功能强大的条件构造器
Wrapper
。使用它可以让我们非常方便的构造条件。 - 其继承体系如下:
- 在其子类
AbstractWrapper
中提供了很多用于构造Where条件的方法。 AbstractWrapper
的子类QueryWrapper
则额外提供了用于针对Select语法的select
方法。可以用来设置查询哪些列。AbstractWrapper
的子类UpdateWrapper
则额外提供了用于针对SET语法的set
方法。可以用来设置对哪些列进行更新。- 完整的AbstractWrapper方法可以参照:https://baomidou.com/guide/wrapper.html#abstractwrapper
- 介绍是用来干什么的。它的实现类有哪些:QueryWrapper,UpdateWrapper,【LambdaQueryWrapper】
5.2 常用AbstractWrapper方法(重点)
eq:equals,等于
gt:greater than ,大于 >
ge:greater than or equals,大于等于≥
lt:less than,小于<
le:less than or equals,小于等于≤
between:相当于SQL中的BETWEEN
like:模糊匹配。like(“name”,”黄”),相当于SQL的name like ‘%黄%’
likeRight:模糊匹配右半边。likeRight(“name”,”黄”),相当于SQL的name like ‘黄%’
likeLeft:模糊匹配左半边。likeLeft(“name”,”黄”),相当于SQL的name like ‘%黄’
notLike:notLike(“name”,”黄”),相当于SQL的name not like ‘%黄%’
isNull
isNotNull
and:SQL连接符AND
or:SQL连接符ORin: in(“age”,{1,2,3})相当于 age in(1,2,3)
groupBy: groupBy(“id”,”name”)相当于 group by id,name
orderByAsc :orderByAsc(“id”,”name”)相当于 order by id ASC,name ASC
orderByDesc :orderByDesc (“id”,”name”)相当于 order by id DESC,name DESC
1. 示例一
- SQL语句如下:
1 | SELECT |
- 如果用Wrapper写法如下:
1 |
|
2. 示例二
- SQL语句如下:
1 | SELECT |
- 如果用Wrapper写法如下:
1 |
|
3. 示例三
- SQL语句如下:
1 | SELECT |
- 如果用Wrapper写法如下:
1 |
|
5.3 常用QueryWrapper方法
QueryWrapper的 select 可以设置要查询的列。
1. 示例一
select(String… sqlSelect) 方法的测试为要查询的列名
- SQL语句如下:
1 | SELECT |
- MP写法如下:
1 |
|
2. 示例二
select(Class
entityClass, Predicate predicate)
方法的第一个参数为实体类的字节码对象,第二个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。
SQL语句如下:
1 | SELECT |
- MP写法如下:
1 |
|
- 函数式编程
3. 示例三
select(Predicate
predicate)
方法第一个参数为Predicate类型,可以使用lambda的写法,过滤要查询的字段 (主键除外) 。
SQL语句如下:
1 | SELECT |
就是不想查询address这列,其他列都查询了:在匿名内部类加一个!就好,这种写法的优点就是写不要什么什么,相比传统方式效率高。
注意需要传入一个类型为T的entity属性,也就是实体类
new User()
。MP写法如下:
1 |
|
5.4 常用UpdateWrapper方法
- 我们前面在使用update方法时需要创建一个实体类对象传入,用来指定要更新的列及对应的值。但是如果需要更新的列比较少时,创建这么一个对象显的有点麻烦和复杂。
- 我们可以使用UpdateWrapper的set方法来设置要更新的列及其值。同时这种方式也可以使用Wrapper去指定更复杂的更新条件。
1. 示例
- SQL语句如下:
1 | UPDATE |
- 我们想把id大于1的用户的年龄修改为99,则可以使用如下写法:
1 |
|
5.5 Lambda条件构造器
我们前面在使用条件构造器时列名都是用字符串的形式去指定。这种方式无法在编译期确定列名的合法性。
所以MP提供了一个Lambda条件构造器可以让我们直接以实体类的方法引用的形式来指定列名。这样就可以弥补上述缺陷。
也就是编译期间就知道如列名写没写对
1. 示例
- 要执行的查询对应的SQL如下
1 | SELECT |
- 如果使用之前的条件构造器写法如下
1 |
|
- 如果使用Lambda条件构造器写法如下
1 |
|
6.自定义SQL
- 虽然MP为我们提供了很多常用的方法,并且也提供了条件构造器。但是如果真的遇到了复制的SQL时,我们还是需要自己去定义方法,自己去写对应的SQL,这样SQL也更有利于后期维护。
- 因为MP是对mybatis做了增强,所以还是支持之前Mybatis的方式去自定义方法。
- 同时也支持在使用Mybatis的自定义方法时使用MP的条件构造器帮助我们进行条件构造。
- 接下去我们分别来讲讲。
6.0 准备工作
- 准备数据
1 | CREATE TABLE `orders` ( |
- 创建实体类
1 |
|
6.1 Mybatis方式
1. 定义方法
- 在Mapper接口中定义方法
1 | public interface UserMapper extends BaseMapper<User> { |
2.创建xml
- 先配置xml文件的存放目录
1 | mybatis-plus: |
- 创建对应的xml映射文件
3. 在xml映射文件中编写SQL
- 创建对应的标签,编写对应的SQL语句
1 |
|
6.2 Mybatis方式结合条件构造器
- 我们在使用上述方式自定义方法时,如果也希望我们的自定义方法能像MP自带方法一样使用条件构造器来进行条件构造的话只需要使用如下方式即可。
- 也就是我们可以自定义wapper,但是要注意拼接sql语句。
- 方法定义中添加Warpper类型的参数
- 添加Warpper类型的参数,并且要注意给其指定参数名。
1 | public interface UserMapper extends BaseMapper<User> { |
- 在SQL语句中获取Warpper拼接的SQL片段进行拼接。
1 | <select id="findMyUserByWrapper" resultType="com.sangeng.domian.User"> |
- 注意:不能使用#{}应该用${}
- 二者区别:${}有预编译(提示)功能,#{}没有
7.分页查询
7.1 基本分页查询
- 配置分页查询拦截器
1 |
|
- 进行分页查询
1 |
|
7.2 多表分页查询
- 如果需要在多表查询时进行分页查询的话,就可以在mapper接口中自定义方法,然后让方法接收Page对象。
1. 示例
- 需求:我们需要去查询Orders表,并且要求查询的时候除了要获取到Orders表中的字段,还要获取到每个订单的下单用户的用户名。
- 准备工作:
- SQL准备
1 | SELECT |
- 实体类修改:
- 增加一个userName属性
1 |
|
2. 实现
- 定义接口,定义方法:
- 方法第一个测试定义成Page类型
1 | public interface OrdersMapper extends BaseMapper<Orders> { |
- 在xml中不需要关心分页操作,MP会帮我们完成。
1 |
|
- 然后调用方法测试即可:
1 |
|
8.Service 层接口
- MP也为我们提供了Service层的实现。我们只需要编写一个接口,继承
IService
,并创建一个接口实现类继承ServiceImpl
,即可使用。 - 相比于Mapper接口,Service层主要是支持了更多批量操作的方法。
- 总结:连impl方法都给你提供好了
8.1 基本使用
1. 改造前
- 定义接口
1 | public interface UserService { |
- 定义实现类
1 |
|
2. 改造后
- 接口
1 | public interface UserService extends IService<User> { |
- 实现类
1 |
|
- 测试
1 |
|
8.2自定义方法
1 | public interface UserService extends IService<User> { |
1 |
|
9.代码生成器
- MP提供了一个代码生成器,可以让我们一键生成实体类,Mapper接口,Service,Controller等全套代码 。使用方式如下
1. 添加依赖
1 | <!--mybatisplus代码生成器--> |
2. 生成
- 修改相应配置后执行以下代码即可
1 | public class GeneratorTest { |
MybatisPlus-高级篇
1.自动填充:
在实际项目中的表会和我们的orders表一样,有更新时间,创建时间,创建人,更新人等字段。
我们可以使用
@TableField
的fill
属性来设置字段的自动填充。让我们能更方便的更新相关字段。
1.1 示例
- 在对应字段上增加注解:
- 使用TableField注解的fill属性来标注哪些字段需要在自动填充,加了注解MP才会在对应的SQL中为我们预留字段。而属性值代表我们在什么进行什么操作时需要预留字段。
1 | /** |
- 自定义填充处理器 MetaObjectHandler
1 |
|
2.逻辑删除
MP也支持逻辑删除的处理。我们只需要配置好逻辑删除的实体字段名,代表删除的字段值和代表未删除的字段值后即可。
注意:如果3.3.0版本之前还需要在对应的字段上加上
@TableLogic
注解
1 | mybatis-plus: |
3.乐观锁
并发操作时,我们需要保证对数据的操作不发生冲突。乐观锁就是其中一种方式。乐观锁就是先加上不存在并发冲突问题,在进行实际数据操作的时候再检查是否冲突。
我们在使用乐观锁时一般在表中增加一个version列。用来记录我们对每天记录操作的版本。每次对某条记录进行过操作是,对应的版本也需要+1。
然后我们在每次要进行更新操作时,先查询对应数据的version值。在执行更新时, set version = 老版本+1 where version = 老版本
如果在查询老版本号到更新操作的中间时刻有其他人更新了这条数据,这样这次更新语句就会更新失败。
这里在更新时对version的操作如果有我们自己做就会显的有点麻烦。所以MP提供了乐观锁插件。
使用后我们就可以非常方便的实现对version的操作。
3.1 使用
- 配置对应插件
1 |
|
- 在实体类的字段上加上
@Version
注解
1 |
|
更新
注意:在更新前我们一定要先查询到version设置到实体类上再进行更新才能生效
1 |
|
- 这种情况下我们可以看到执行的sql已经发生了变化。
1 | ==> Preparing: UPDATE orders SET price=?, update_time=?, version=? WHERE id=? AND version=? AND del_flag=0 |
3.2 多插件配置问题
我们在使用3.4.0版本以后的MP时,如果需要用到多个插件的话要注意。在配置的时候只需要注入一个MybatisPlusInterceptor 对象,把插件对象添加到MybatisPlusInterceptor 对象中即可。
例如:
1 |
|
- 注意顺序: