最近用Mybatis-plus比较多,这个框架带来的快速开发的效果也比较好,但是,由于技术架构的时间较长,开发团队的不断更新,导致程序设计及开发出现了问题,
注释:该部分代码分析版本来自于Mybatis-plus 3.4.0 版本不同可能有细微差异,仅供参考
(虽然我不觉得这部分基础代码会在版本迭代下进行较大的改动)
问题1:
create_time 字段从 因为项目组开发人员不断更新 历史实体类中createTime 默认的 Date类型 在新增的实体类中手中变成了 LocalDateTime 这本身没有什么问题,但是。。。
导致:
新实体类中 在 createTime 字段上 添加 @TableFiled(fill = INSERT) 产生自动注入失败 的问题
原因是:
new Date() 产生的数据是 CST 格式 无法放入 LocalDateTime
结果:
我们的 每个新的实体类 只要采用了 LocalDateTime 的字段设计 就只能用 setCreateTime(LocalDateTime.now()) 的方式来完成时间数据的注入
这就令人很是烦躁!!! 不过,也同样侧面说明了,虽然目前市面上提供的java工具很好用,但要完全兼容历史架构,需要对历史架构足够熟悉,否则,也会影响真实的开发效率
问题2
那createTime没办法偷懒了,我得想办法偷别的字段的懒 !!!要么多对不起程序员,然后就出问题了
这次bug十分意外,在插入createBy的时候,又出现了时间问题???
而且,这次排查的bug还让我学到了一些小东西
排查bug
其实这个bug排查的时间也不久,可以预见性知道一定是注入的问题,但一个决定性问题影响了我的思路
就是在我认知中 Mybatis-plus 应该是只对加了 @TableField(fill = FieldFill.INSERT)
的注解进行添加的方法,但让我万万没想到的是,实际上不是这个样子的
翻阅一下Mybatis-plus的插入/更新源码
其实入参实体就是我们携带了 @TableField(fill = FieldFill.INSERT)
所在的 实体类
大概可以理解为:
public class User{
@TableId(type = IdType.ASSIGN_UUID)
private String id;
@TableField(fill = FieldFill.INSERT)
private String name ;
}
这个样子,就是 可以理解为 MateObject
的 数据结构 包含了 这个实体类的,及相关的注解详情
主键生成策略这部分。和我关注这部分关联性不高,直接跳过
第一个全局的开启,默认是开启的 可以在实现了 MetaObjectHandler
接口的类下内重写这个方法 直接返回 false
即可关闭
第二个的话,比较神奇,是在启动的时候初始化 entity然后扫描到这个实体类中是否存在了 @TableField(fill = FieldFill.INSERT)
注解,只要有一个存在,就为 true
(坑点就在这里)
最终的结果走进了判断, 触发了我心心念念的 metaObjectHandler.insertFill(metaObject)
方法
但是metaObject中包含的是整个实体类! createTime
也在其中啊!!直接把我的createTime给干掉了,报了个和问题1
,一模一样的错误。。
原因
找到原因了,原来是@TableField(fill = FieldFill.INSERT)
在实体类中 只要有一个,就会渲染将整个实体类标注为开启自动填充(虽然没什么问题,但是我最开始是认为精细到字段的,不翻还真的不知道)
结果
为了项目稳定,不再引发其他连锁反应,我没敢动 这个Mybatis的自动插入代码
就是实现了 MetaObjectHandler
接口的类,并实现了 insertFill(MetaObject metaObject)
方法 的这个 处理器
其实有一个解决办法,就是我一定要将将所有包含createTime
的实体类在 insert
前,触发一次setCreateTime(LocalDateTime.now)
然后再insertFill中做一个判空,就可以解决这个问题,这就属于约定大于配置了。
但,为了防止其他问题,就只能,用setCrateBy(Security.getUserName())
和setCreateTime(LocalDateTime.now)
来委屈我疲惫的大猪蹄子了。
好像是第一次在掘金上发布文章,东西不难,不过场景很少见(毕竟是历史开发人员和新开发人员思维上的冲突),不过,还是希望后续有人避免遇见像我这样的bug,祝:各位看博文的朋友们都能遇见百万并发的项目