MybatisPlus自动填充功能和乐观锁处理功能
前提: 数据库表一般都需要有 create_time和update_time字段,这两个字段的值可以通过数据库级别进行自动填充,但是通常在公司中不允许直接修改数据库。
通过MybatisPlus实现自动填充功能
数据库表

pojo类
@Data
public class AdminUser {
//使用基本类型包装类
/* 枚举类型的值含义
AUTO(0), //数据库id自增1
NONE(1), //未设置主键
INPUT(2), //手动输入
ID_WORKER(3), //默认的全局唯一id
UUID(4), //全局唯一id uuid
ID_WORKER_STR(5); // ID_WORKER的字符串表示法
*/
//mybatisPlus主键生成策略:雪花算法,自动生成的ID全球唯一,Long类型
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
private String nickName;
private Byte locked;
@TableField(fill = FieldFill.INSERT) //插入的时候
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) //插入完更新的时候
private Date updateTime;
}
元对象处理类
- insertFill方法,插入时自动填充策略(插入数据时,更新时间和插入时间相同)
- updateFill方法,更新时自动填充策略
//元对象处理类
@Component //把处理器加到IOC容器中
@Slf4j
public class MyMetaObjectHandle implements MetaObjectHandler {
//插入时填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充");
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//修改时填充策略
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
乐观锁处理功能
数据库表
- 添加一个version字段,默认值是1

pojo
@Data
public class AdminUser {
//mybatisPlus主键生成策略:雪花算法,自动生成的ID全球唯一,Long类型
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
private String nickName;
private Byte locked;
@TableField(fill = FieldFill.INSERT) //插入的时候填充
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) //插入完更新的时候填充
private Date updateTime;
@Version
private Integer version; //乐观锁字段
}
配置类
- 注册乐观锁插件
@Configuration //表明该类是一个配置类
@EnableTransactionManagement //自动管理事务注解
@MapperScan("com.rm.dao") //扫描mapper接口
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
//注意mybatisPlus版本,3.4.0以上有这个类
public MybatisPlusInterceptor MybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
启动测试的时候碰到了缓存满了,报了CodeCache is full. Compiler has been disabled.
解决:将项目缓存改大一点

测试乐观锁
//测试乐观锁成功,单线程
@Test
public void testOptimisticLocker(){
//alt+shift+insert 进入多行操作模式
//通过ID获取对象
AdminUser user = adminUserMapper.selectById(1L);
//修改对象
user.setNickName("我是管理员");
//更新操作
adminUserMapper.updateById(user);
}
查看日志
- 执行更新的时候将version字段也带上了
==> Preparing:
UPDATE admin_user
SET user_name=?, password=?, nick_name=?, locked=?, update_time=?, version=?
WHERE id=? AND version=?
==> Parameters:
admin(String), e10adc3949ba59abbe56e057f20f883e(String),
我是管理员(String), 0(Byte), 2021-06-02 15:59:43.816(Timestamp), 2(Integer),
1(Long), 1(Integer)
测试乐观锁失败情况
@Test
//测试乐观锁失败 模拟多线程
public void testOptimisticLocker2(){
//通过ID获取对象
AdminUser user1 = adminUserMapper.selectById(1L);
//修改对象
user1.setNickName("我是管理员1");
//user1设置值了但是还没有执行更新操作
AdminUser user2 = adminUserMapper.selectById(1L);
user2.setNickName("我是管理员2");
//user2已经设置值并执行了更新操作
adminUserMapper.updateById(user2);
//user1再次执行更新操作就会失败,因为查不到user2更新前的version
//如果没有乐观锁的情况下,执行更新操作会覆盖user2的值
adminUserMapper.updateById(user1);
}
查看日志
- user2对象执行更新操作成功
==> Preparing:
UPDATE admin_user
SET user_name=?, password=?, nick_name=?, locked=?, update_time=?, version=?
WHERE id=? AND version=?
==> Parameters:
admin(String), e10adc3949ba59abbe56e057f20f883e(String),
我是管理员2(String), 0(Byte), 2021-06-02 16:10:28.29(Timestamp), 3(Integer),
1(Long), 2(Integer) //where条件
<== Updates: 1
- user1对象执行更新操作失败
- 由于user2对象已经执行了更新操作,version变为了3,此时再查询version=2就查不到数据了
==> Preparing:
UPDATE admin_user
SET user_name=?, password=?, nick_name=?, locked=?, update_time=?, version=?
WHERE id=? AND version=?
==> Parameters: admin(String), e10adc3949ba59abbe56e057f20f883e(String),
我是管理员1(String), 0(Byte), 2021-06-02 16:10:28.308(Timestamp), 3(Integer),
1(Long), 2(Integer)
<== Updates: 0
mybatisPlus查询操作
通过多个id进行查询
//测试查询多个用户
@Test
public void testBatchSelect(){
//查询id为1和2的用户
List<AdminUser> list = adminUserMapper.selectBatchIds(Arrays.asList(1, 2));
for (AdminUser adminUser : list) {
System.out.println(adminUser);
}
}
根据条件进行查询
- 使用map进行操作
@Test //测试根据条件查询
public void testCondition(){
HashMap<String, Object> map = new HashMap<>();
map.put("user_name","admin"); //键是数据库字段
List<AdminUser> list1 = adminUserMapper.selectByMap(map);
for (AdminUser adminUser : list1) {
System.out.println(adminUser);
}
}
日志
==> Preparing:
SELECT id,user_name,password,nick_name,locked,create_time,update_time,version
FROM admin_user
WHERE user_name = ?
==> Parameters:
admin(String)
<== Columns:
id, user_name, password, nick_name, locked, create_time, update_time, version
<== Row:
1, admin, e10adc3949ba59abbe56e057f20f883e, 我是管理员2, 0, null,
2021-06-02 16:10:28, 3
分页查询功能
注册分页插件
@Configuration //表明该类是一个配置类
@EnableTransactionManagement //自动管理事务注解
@MapperScan("com.rm.dao") //扫描mapper接口
public class MyBatisPlusConfig {
//注册乐观锁插件
@Bean
//注意mybatisPlus版本,3.4.0以上有这个类
public MybatisPlusInterceptor MybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
//注册分页插件
// 最新版 3.4.0以上
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// DbType.MYSQL参数为空时会自动根据url查询对应的数据库
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
测试分页功能
@Test //测试分页查询
public void tsetPage(){
//当前页是1,一页显示5条数据
Page<AdminUser> page = new Page<>(2,3);
adminUserMapper.selectPage(page, null);
List<AdminUser> userList = page.getRecords();
for (AdminUser adminUser : userList) {
System.out.println(adminUser);
}
}
查看日志
- 先查询出来数据总数
- 每页显示3条,从第二页查,所以是查询第4,5,6条数据
==> Preparing: SELECT COUNT(1) FROM admin_user
==> Parameters:
<== Columns: COUNT(1)
<== Row: 7
==> Preparing:
SELECT id,user_name,password,nick_name,locked,create_time,update_time,version
FROM admin_user
LIMIT ?,?
==> Parameters:
3(Long), 3(Long)
<== Columns:
id, user_name, password, nick_name, locked, create_time, update_time, version
<== Row:
4, cxnph, 123456, 测试2号, 0, 2021-06-02 16:44:02, 2021-06-02 16:44:02, 1
<== Row:
5, cxnph, 123456, 测试2号, 0, 2021-06-02 16:44:11, 2021-06-02 16:44:11, 1
<== Row:
6, cxnph, 123456, 测试2号, 0, 2021-06-02 16:44:19, 2021-06-02 16:44:19, 1
<== Total: 3

浙公网安备 33010602011771号