MyBatis-Puls简介

(1)MyBatis-Plus(简称MP),是MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发,提高效率而生

(2)MyBatis-Puls特性

特性简介
无侵入只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作,BaseMapper
强大的 CRUD 操作内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作, 更有强大的条件构造器,满足各类使用需求,简单的CRUD操作不用自己编写
支持 Lambda 形式调用通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作支持全局通用方法注入( Write once, use anywhere )
内置代码生成器采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码, 支持模板引擎,更有超多自定义配置等您来使用(自动生成代码)
内置分页插件基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 分页插件支持多种数据库:MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

BaseMapper<T>接口

MyBatis-Plus中的基本CRUD在内置的BaseMapper<T>接口中都已得到了实现,因此继承该接口后可以直接使用其中的方法

增加Insert)

1
2
// 插入一条记录
int insert(T entity);

删除(Delete)

1
2
3
4
5
6
7
8
9
10
11
// 根据 ID 删除
int deleteById(Serializable id);

// 根据ID 批量删除
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

修改(Update)

1
2
3
4
5
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);

查询(Selete)

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
// 根据 ID 查询
T selectById(Serializable id);

// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据ID 批量查询
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 columnMap 条件查询
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并分页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询全部记录(并分页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

通用Service服务

MyBatis-Plus中有一个Iservice<T>接口和其实现类ServiceImpl,封装了常见的业务层逻辑,泛型 T 为任意实体对象,在使用的时候仅需在自己定义的Service接口中继承IService接口,在自己的实现类中实现自己的Service并继承ServiceImpl即可

增加(Save、SaveOrUpdate)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);

// 插入(批量)
boolean saveBatch(Collection<T> entityList);

// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);

// 若 TableId 注解存在则更新记录,否插入一条记录
boolean saveOrUpdate(T entity);

// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);

// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);

// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

删除(Remove)

1
2
3
4
5
6
7
8
9
10
11
// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);

// 根据 ID 删除
boolean removeById(Serializable id);

// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);

// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

修改(Update)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);

// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);

// 根据 ID 选择修改
boolean updateById(T entity);

// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);

// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);

查询(Get、List、Count)

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
// 根据 ID 查询
T getById(Serializable id);

// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);

// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);

// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);

// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

// 查询所有
List<T> list();

// 查询列表
List<T> list(Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);

// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);

// 查询所有列表
List<Map<String, Object>> listMaps();

// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);

// 查询全部记录
List<Object> listObjs();

// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);

// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);

// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

// 查询总记录数
int count();

// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

分页(Page)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 根据 ID 查询
T getById(Serializable id);

// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);

// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);

// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);

// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

常用注解

注解简介
@TableName用于标识实体类对应的表名,在实体类类型上添加@TableName(“t_user”)
@TableId将某个属性对应的字段标识为主键
value属性:用于指定表中的主键字段
type属性:定义主键策略,默 认为IdType.ASSIGN_ID
IdType.ASSIGN_ID:基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
IdType.AUTO:使用数据库的自增策略,数据库需要设置了id自增, 否则无效
@TableField设置属性所对应的字段名,如果没有对应字段则设置exist=false
@TableLogic设置逻辑删除,1已删除,0未删除,使用场景:可以进行数据恢复
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:虚假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// @TableName注解:设置实体类对应的表名
@TableName("t_user")
public class User {
// @TableId注解:将某个属性对应的字段标识为主键
// value属性:用于指定表中的主键字段
// type属性:设置主键生成策略
@TableId(value = "id", type = IdType.AUTO)
private Long id; // id
// @TableField注解:设置属性所对应的字段名
@TableField("username")
private String username; // 用户名
private String password; // 密码
private String gender; // 性别
private Integer age; // 年龄
private String email; // 邮箱
// @TableLogic注解:设置逻辑删除
@TableLogic
private Integer isDelted; // 逻辑删除
}

条件构造器

(1)MP提供了条件构造器Wrapper,可以方便实现稍复杂点的条件查询,很复杂的还是要xml编写sql

(2)mp的条件构造抽象类的结构

抽象类简介
Wrapper条件构造抽象类,最顶端父类
AbstractWrapper用于查询条件封装,生成 sql 的 where 条件
QueryWrapperEntity 对象封装操作类,不是用lambda语法
UpdateWrapperUpdate 条件封装,用于Entity对象更新操作
AbstractLambdaWrapperLambda 语法使用 Wrapper统一处理解析lambda获取数据库字段
LambdaQueryWrapper用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapperLambda 更新封装Wrapper

常用配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# MyBatis-Plus相关配置
mybatis-plus:
configuration:
#配置日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 全局配置
global-config:
db-config:
# 设置所有表的通用前缀名称为t_
table-prefix: t_
# 设置主键的生成策略(assign_id雪花算法,auto自增)
id-type: auto
logic-delete-field: delFlag # 逻辑删除的字段
logic-delete-value: 1 # 代表已删除
logic-not-delete-value: 0 #代表未删除
# 自定义映射文件路径,默认为mapper/**/*.xml
mapper-locations: mapper/**/*.xml
# 配置类型别名所对应的包
type-aliases-package: com.wen.pojo
# 扫描通用枚举的包
type-enums-package: com.wen.enums

配置分页

(1)创建MybatisPlusConfig配置类

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
@Configuration// @Configuration注解:将类标识为配置类
@MapperScan("com.wen.mapper")// 扫描 指定 文件夹
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置是否进行优化连接查询,默认为false
paginationInnerInterceptor.setOptimizeJoin(true);
// 设置数据库类型,可选值:DbType.MYSQL、DbType.ORACLE等,默认为DbType.MYSQL
paginationInnerInterceptor.setDbType(DbType.MYSQL);
// 设置分页溢出总页数是否进行处理,默认为false
paginationInnerInterceptor.setOverflow(true);
// 将分页插件添加到拦截器链中
interceptor.addInnerInterceptor(paginationInnerInterceptor);
// 乐观锁插件
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
// 将乐观锁插件添加到拦截器链中
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return interceptor;
}

}

(2)测试使用案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
void testPage() {
// 设置分页,Page(当前页码,每页条数)
Page<User> page = new Page<>(2, 5);
// 分页查询,null是查询条件
userMapper.selectPage(page, null);
// 是否有下一页
System.out.println("是否有下一页:"+page.hasNext());
// 是否有上一页
System.out.println("是否有上一页:"+page.hasPrevious());
// 当前页码值
System.out.println("当前页码值:" + page.getCurrent());
// 每页显示数
System.out.println("每页显示数:" + page.getSize());
// 总记录数(数据总量)
System.out.println("总记录数:" + page.getTotal());
// 总页面数
System.out.println("总页面数:" + page.getPages());
// 详细数据
System.out.println("详细数据:" + page.getRecords());
}

属性自动填充

MetaObjectHandler接口是mybatisPlus提供的扩展接口,可以在插入或者更新数据的时候,为一些字段指定默认值。实现这个需求的方法不止一种,在sql层面也可以做到,在建表的时候也可以指定默认值。

(1)实体类上边加上@TableField注解指定进行属性填充的时机(更新、插入、或者更新和插入)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@SuppressWarnings("serial")// @SuppressWarnings注解是jse提供的注解,屏蔽无关紧要的警告。
@Data// 代表get、set、toString、equals、hashCode等操作
@NoArgsConstructor// 代表无参构造
@AllArgsConstructor// 代表全参构造
@TableName("comment")// MyBatis-Puls提供的注解,设置实体类对应的表名
public class Comment {
// 评论发表者id(谁评论的)
@TableField(fill = FieldFill.INSERT)//插入时,填充字段
private Long createBy;

//评论发表时间
@TableField(fill = FieldFill.INSERT)//插入时,填充字段
private Date createTime;

//评论更新者
@TableField(fill = FieldFill.INSERT_UPDATE)// 插入或更新时,填充字段
private Long updateBy;

//评论更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)// 插入或更新时,填充字段
private Date updateTime;
}

(2)类实现MetaObjectHandler接口,重写里面的方法

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
/**
* mybatisPlus属性自动填充配置,,对应的实体类字段上需要加 @TableField(fill = FieldFill.INSERT_UPDATE)
* 插入数据自动插入公共字段createBy、createTime、updateBy、updateTime
* 更新数据自动更新公共字段updateBy、updateTime
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时自动填充
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("插入时自动填充");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("createBy", "123", metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("updateBy", "123", metaObject);
}

/**
* 更新时自动填充
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("更新时自动填充");
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName(" ", "123", metaObject);
}
}