Mybatis-plus自动填充不生效或自动填充数据为null原因及解决方案
作者:五更依旧朝花落 发布时间:2021-08-16 02:18:42
昨天使用mybatis-plus。使用自动填充后发现了两个问题。
一个是填充数据为null,
一个是当使用了mybatis-plus的乐观锁,自动填充就失效了
开始在网上看,有人说是mybatis的bug,我想不会我这么快就遇到了bug。后面我通过idea的(ctrl+B)看他的源码.发现这不是bug,而是一个非常巧妙的设计,当然也可能是之前有bug,我用的版本是正常的
mybatis官网自动填充功能说明
我使用的版本是3.3.2
如果想省时间,前面的问题描述和分析过程不用看,直接根据目录跳到小结就好了。
问题一:自动填充的数据为null
原因:[填充的数据类型] 和 [实体类定义的数据类型] 不一致。例如你的updateTime是 java.util.Date类型的。但是填充的是LocalDateTime(因为官网给个就是这个,可能就是直接用了)。这就会导致填充的数据为空。
参考如下定义
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
以下是官网给的示范:(我把那两个过期方法去掉了)
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
? ? @Override
? ? public void insertFill(MetaObject metaObject) {
? ? ? ? log.info("start insert fill ....");
? ? ? ? this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
? ? ? ? this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
? ? ? ? /* 上面选其一使用,下面的已过时(注意 strictInsertFill 有多个方法,详细查看源码) */
? ? ? ?
? ? }
? ? @Override
? ? public void updateFill(MetaObject metaObject) {
? ? ? ? log.info("start update fill ....");
? ? ? ? this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
? ? ? ? this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
? ? ? ? /* 上面选其一使用,下面的已过时(注意 strictUpdateFill 有多个方法,详细查看源码) */
? ? }
}
问题二:使用mybatis-plus的乐观锁后发现自动填充的updateTime字段不自动填充了
该问题还有其他描述:从数据库查出来的数据,无法进行自动填充
本质原因:当该字段有值之后,自动填充不进行填充,里面的数据还是原值
下面两段代码,testUpdateUser和testOptimisticLocker。前者updateTime进行了自动填充,后者没有进行自动填充。
原因是后者的User对象所有字段的值都从数据库查出来,并进行了赋值。然后自动填充数据没有填充数据
示例:
@Test
public void testUpdateUser(){
User user = new User();
user.setId(7L);
user.setName("喻文波");
int rows = userMapper.updateById(user);
System.out.println(rows);
}
/**
* 测试乐观锁
*/
@Test
public void testOptimisticLocker(){
// 先查询一个用户
User user = userMapper.selectById(8L);
System.out.println(user);
// 修改用户观察version是否更新
user.setName("pdd");
user.setEmail("PDD@163.com");
int rows = userMapper.updateById(user);
System.out.println(rows);
}
原因:
填充用的方法是:this.fillStrategy(metaObject,"updateTime",new Date());,这是官网提供的方法之一
我们ctrl+B进去看下
default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) {
? ? ? ? if (this.getFieldValByName(fieldName, metaObject) == null) {
? ? ? ? ? ? this.setFieldValByName(fieldName, fieldVal, metaObject);
? ? ? ? }
? ? ? ? return this;
? ? }
发现就是故意这样设计的,当你要填充的字段 fieldName对应的字段为空时才进行自动填充,否则不进行填充
然后我又看了官网提供的另一个方法this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
ctrl+B 看下源码
最终调用的是下面这个。有点长。一看就不想看
然后我strict的意思,严格的。我推测这个应该就是说强制执行的意思,不管是否有原值都强制执行更新。然后我试了下,果然就是这样的
? ? default MetaObjectHandler strictFill(boolean insertFill, TableInfo tableInfo, MetaObject metaObject, List<StrictFill> strictFills) {
? ? ? ? if (insertFill && tableInfo.isWithInsertFill() || !insertFill && tableInfo.isWithUpdateFill()) {
? ? ? ? ? ? strictFills.forEach((i) -> {
? ? ? ? ? ? ? ? String fieldName = i.getFieldName();
? ? ? ? ? ? ? ? tableInfo.getFieldList().stream().filter((j) -> {
? ? ? ? ? ? ? ? ? ? return j.getProperty().equals(fieldName) && i.getFieldType().equals(j.getPropertyType()) && (insertFill && j.isWithInsertFill() || !insertFill && j.isWithUpdateFill());
? ? ? ? ? ? ? ? }).findFirst().ifPresent((j) -> {
? ? ? ? ? ? ? ? ? ? this.strictFillStrategy(metaObject, fieldName, i.getFieldVal());
? ? ? ? ? ? ? ? });
? ? ? ? ? ? });
? ? ? ? }
? ? ? ? return this;
? ? }
最后总结:
insert也是一样的。
? ?@Override
? ? public void updateFill(MetaObject metaObject) {
? ? ? ? // 如果有值,则不会更新
? ? ? ?// this.fillStrategy(metaObject,"updateTime",new Date());
? ? ? ? // 即使有值,也更新为当前时间
? ? ? ?this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
? ? }
小结
填充的方法一共有三个
// 这个是通用的,插入和更新都可以使用 但是当字段存在值 的时候不进行填充
this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug请升级到之后的版本如`3.3.1.8-SNAPSHOT`)
// 这个是insert的时候用的,插入的时候时候强制进行填充
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
// update的时候使用,更新的时候强制进行填充
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
注意填充的类型,要和你定义字段的类型一致,不然就可能出现填充为为空值的情况 例如原值是java.util.Date ,填充的LocalDateTime就会出现这种情况
来源:https://blog.csdn.net/m0_37628958/article/details/106633132


猜你喜欢
- 前言需求使用freemarker生成的静态文件,统一存储在某个服务器上。本来一开始打算使用ftp实现的,奈何老连接不上,改用jsch。毕竟有
- 引言朋友要查看一个已存在包的versionCode信息,在群里面询问,由于是已经存在的apk包,并且只需要其中的versionCode信息,
- 一、内部类1.内部类的概念内部类是定义在类中的类。内部类把逻辑上相关的类放在一起。而有的内部类不会在其他地方用到,它没有类名,在定义的时候就
- 提示:建议一定要看后面的@RequestBody的核心逻辑源码以及六个重要结论!本文前半部分的内容都是一些基本知识常识,可选择性跳过。声明:
- 前言在日常开发中我们经常会将JSON、XML、HTML、SQL、Regex等字符串拷贝粘贴到我们的代码中,而这些字符串往往包含很多的引号&q
- 这篇文章主要介绍了SpringBoot2整合activiti6环境搭建过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定
- 目录前言闲扯使用技术所需知识储备实现步骤总结前言现代互联网项目中,很多场景下都需要使用一种叫做验证码的技术,常用的有图片验证码,滑块验证码,
- ava最明显的一个优势就是它的内存管理机制。你只需简单创建对象,java的垃圾回收机制负责分配和释放内存。然而情况并不像想像的那么简单,因为
- 本文介绍了Spring Boot Admin监控服务上下线邮件通知,分享给大家,具体如下:微服务架构下,服务的数量少则几十,多则上百,对服务
- 问题:写了一个新的dao接口,进行单元测试时提示:Initialization of bean failed; nested excepti
- 先建个钉钉群,并加好机器人此时,机器人已经添加完毕,接下来编写我们连接机器人小哥的代码import com.alibaba.fastjson
- 前言可能有人会有疑问,为什么外面已经有更好的组件,为什么还要重复的造轮子,只能说,别人的永远是别人的,自己不去造一下,就只能知其然,而不知其
- 前言开发做得久了,总免不了会遇到各种坑。而在Android开发的路上,『软键盘挡住了输入框』这个坑,可谓是一个旷日持久的巨坑——来来来,我们
- using System;using System.Collections;using System.IO;namespace Consol
- 总结并复现了一下Unsafe在安全领域的一些应用0 前言unsafe里面有很多好用的方法,比如allocateInstance可以直接创建实
- 前言为了减少日志频繁打印带来的性能影响,线上环境设置的日志级别一般都相对较高。而当出现生产问题需要排查的时候,可能需要适当降低日志级别(例如
- /// 删除文件和目录public class Cleaner { /// /// 删除指
- Android 中Activity 之间传递参数1.传递简单数据在A Activity中findViewById(R.id.startBAc
- 1、概念:MyBatis中的延迟加载,也称为懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。例如在进行一
- 如下所示:using System;using System.Collections.Generic;using System.Diagno