Mybatis-plus
Mybatis-plus框架入门
引入依赖
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
mapper简化
数据源和原生的mybatis配置一样
@Repository
public interface UserMapper extends BaseMapper<User>{
}
通过继承BaseMapper类,从而直接继承了常规的CRUD方法,避免大量重复代码的编写,将实体类写入BaseMapper的泛型中。
不要忘了在启动类上加上MapperScan注解开启mapper扫描
查看sql日志
在配置文件中添加:
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
ID的生成策略
在Mybatis-plus框架中,可以指定不同的ID生成策略,只需要在需要指定的ID属性上加上@TableId注解,注解中指定Type属性,就能实现不同的ID生成。
也可以设置全局的主键生成策略,在配置文件中配置:
# 全局采用自增策略
mybatis-plus.global-config.db-config.id-type=auto
自增策略
自增策略采取表中的主键依次自增,在分表的时候,新表的ID生成需要首先查询前一张表的最后一个ID,然后再+1,会影响执行效率,但是便于主键的排序。
@TableId(type = IdType.AUTO)//IdType.AUTO 自增策略
private Long id;
UUID生成ID
使用UUID生成完全随机数,在分表时不需要再查询上一张表的ID信息,可以直接生成,但是这样的完全随机数不利于对表的排序操作
@TableId(type = IdType.UUID)//IdType.AUTO UUID策略
private Long id;
redis生成ID
由于redis是单线程的,所以可以用redis来生成ID,用redis的原子操作INCR和INCRBY来实现
例如:在集群环境下有5太redis,江浙舞台redis编号1,2,3,4,5,然后每台redis生成的ID值都是+5,如下:
A: 1 6 11 16 21
B: 2 7 12 17 22
C: 3 8 13 18 23
D: 4 9 14 19 24
E: 5 10 15 20 15
这样redis生成的ID既不需要在分表的时候查询前表,也能实现对表的排序操作
@TableId(type = IdType.INPUT)//IdType.INPUT 自定义策略
private Long id;
@TableId(type = IdType.NONE)//IdType.NONE 无策略
private Long id;
mybatis-plus生成id(默认)
Mybatis-plus采用的雪花算法,生成的是有序的随机数,大多采取这种主键ID的方案
@TableId(type = IdType.ID_WORKER)//IdType.ID_WORKER mybatis-plus默认策略
private Long id;
//当id为String类型时
@TableId(type = IdType.ID_WORKER_STR)//IdType.ID_WORKER_STR mybatis-plus默认策略
private Long id;
自动填充
自动填充是用mybatis-plus的方式来实现对一些系统生成的字段的生成,例如:create_time,update_time
配置需要填充的字段
@TableField(fill = FieldFill.INSERT)//这里的FieldFill.INSERT表示此字段在执行insert操作的时候填充
private Date createTime;
填充时机的枚举类型包括:
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
配置填充执行器
填充逻辑需要创建一个类,实现MetaObjectHandler接口的方法,并且需要将此类加入ioc容器中
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {//使用mapper的insert操作,就会执行此方法
this.setFieldValByName("createTime",new Date(),metaObject);//根据名称设置填充值
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {//使用mapper的修改操作,这个方法会执行
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁
乐观锁是为了解决写操作的更新失效的问题,通过记录版本号,实现对数据的正常更新。
乐观锁的实现步骤
- 首先需要在数据库表中添加一个字段用来记录版本号
ALTER TABLE USER ADD COLUMN 'version' INT;
- 然后在表对应的实体类中的版本号属性前加上@Version注解,表明这是版本号
@Version
private Integer version;
- 在配置类中注册乐观锁插件(官网直接复制)
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
- (可选)为了使版本号默认,可以在insert数据时自动填充为初始值
分页插件
mybatis-plus中整合了分页,只需要配置分页插件就能实现分页功能。
分页插件的使用步骤
- 配置分页插件的bean
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
- 编写分页的逻辑
//分页查询
@Test
void testSelectByPage(){
Page<User> page=new Page<>(1L,3L);
userMapper.selectPage(page,null);//第二个参数是查询条件
System.out.println(page.getCurrent());//获取当前页
System.out.println(page.getRecords());//获取分页后的数据list
System.out.println(page.getSize());//每页显示的记录数
System.out.println(page.getTotal());//总记录数
System.out.println(page.getPages());//总页数
System.out.println(page.hasNext());//是否有下一页
System.out.println(page.hasPrevious());//是否有上一页
}
==注意==: 在执行了selectPage(page,wrapper)方法之后,所有的分页数据都会存储在page对象中,无需接收返回值
逻辑删除
逻辑删除和物理删除的区别是:
逻辑删除并没有将数据从数据库中删除,而是通过一个字段来设置该数据为删除数据,让查询语句不能查询出这类删除数据。当需要对被删除数据恢复时,只需要将删除的状态修改为未删除即可。
物理删除是将数据从数据库中删除,当需要对被删除的数据做恢复时比较麻烦。
逻辑删除的实现
- 在数据库表中添加一个用于表示逻辑删除的列(deleted)
- 在表的实体类中的逻辑删除属性上加上注解@TableLogic
@TableLogic
private Integer deleted;
- 在配置类中注册逻辑删除的插件
//逻辑删除插件
@Bean
public ISqlInjector sqlInjector(){
return new LogicSqlInjector();
}
- (可选)配置逻辑删除的默认值
#逻辑删除的默认值,1已删除,0未删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
==注意==:逻辑删除实际上执行的是update的操作,只是将逻辑字段更新,并且在执行查询操作的时候会加上逻辑字段=0的条件。
性能分析
mybatis-plus集成了一个性能分析插件,主要用于在开发和测试环境下对sql语句的执行时间的监控和控制
性能分析插件的使用步骤
- 在配置类中注册性能分析插件
/*SQL性能分析插件
* 开发环境使用,线上不推荐,maxTime值得是sql最大执行时长
* */
@Bean
@Profile({"dev","test"})//在dev和test环境下开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
performanceInterceptor.setMaxTime(200);//ms,超过此处设置的ms则sql不执行,并报错
performanceInterceptor.setFormat(true);//是否将sql格式化,默认是false
return performanceInterceptor;
}
- 在配置文件中指定当前的项目环境
#环境设置:dev、test、prod
spring.profiles.active=dev
Wrapper实现复杂查询
mybatis-plus的BaseMapper提供了基本的CRUD方法,但是在还可以从这些基本的方法中自定义一些条件,通过Wrapper可以实现较为复杂的查询(过于复杂的查询只能通过xml配置文件的方式来实现)。
Wrapper的继承体系
//TODO 图片待补充
用QueryWrapper比较多
Wrapper复杂查询的实现步骤
//复杂查询
@Test
public void testWrapper(){
//创建queryWrapper对象
QueryWrapper<User> wrapper=new QueryWrapper<User>();
//ge,gt,le,lt >=,>,<=,<
//wrapper.ge("age",120);
//wrapper.lt("age",30);
//eq,ne ==,!=
//wrapper.eq("name","Jone");
//wrapper.ne("name","Jone");
//between
//wrapper.between("id",1,3);
//like:模糊查询
//wrapper.like("name","j");
//orderByDesc/Asc:排序
//wrapper.orderByDesc("age");
//last:在sql的最后加上一条语句
//wrapper.last("limit 1");
//指定要查询的列
//wrapper.select("id","name");
List<User> users = userMapper.selectList(wrapper);
System.out.println(users);
}