}
心细的小伙伴会不会有个小疑问,为什么我是在 请求结束 时才去清除这个 操作ID,而不是在 AOP 的 After 操作中去做的😄
其实这里是有个小插曲的,一开始我是在 AOP 的 @After 操作中去删除这个 操作ID 的,但是呢 🙄 ,有同事将我改好的日志模块中的部分功能添加到之前的老项目中,而且他直接将这个注解加在 service上,结果系统出现了bug 🙄,还把我拉过去讨论 😒 ,这就很无语了……
image
不过这个 bug 是不难发现的,毕竟这个注解如果加在 service 层面,会存在 service 调用 service 的情况,这样不仅会出现第一个 service 中生成的 操作ID 被第二个 service 覆盖,而且在第二个 service 结束后,操作ID 会被清除掉,但是这个字段是不允许为 null 的,所以就报错了。
按理说,直接加在这个 controller 层面就没问题了,但是讨论过后,在同事的建议下,我也同意对它进行小小的升级下,将这个 清除操作ID 的行为移动到这个 拦截器 中 👇
@Component
public class ThreadLocalInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ThreadLocalUtil.clear();
}
}
感觉这种方式也挺简洁的,在请求结束后直接清掉这个 ThreadLocal 中的内容。🐖
整体设计
接着,我们来看看这个 datalog 的生成。新版的整体思路如下。😋 (画出来清晰多了)
2021-11-12_140557
删除操作
思路如上图~
在删除成功时,要将被删除的数据写到 Log 表 …… 😑
这里有两种情况:(一)根据主键删除 ,这种最简单,我们直接根据主键查出之前的数据即可。(二)根据其他条件删除,这里我们自定义获取主键的方法以便复用上面的方法。
这里就不得不提下这个 MybatisPlus 的好处了~ ,借用 BaseMapper 的 selectBatchIds 方法,我们可以很轻松的
查询出这些数据出来。
image-20211112142253855
因为在使用 MybatisPlus 时,我们会生成相应的 Mapper 方法,而这里就很好地体现了 Java 多态 的特点,我们只需要调用 (BaseMapper) SpringUtil.getBean(XXXMapper.class).selectBatchIds(result) ;即可实现。😄
所以将这个参数挂在 @MethodLog 注解上即可。
@Mapper
public interface XXXMapper extends BaseMapper {
}
而在旧版本中,由于没有用到 MybatisPlus ,自然写了很多的 删除语句 😱
而且由于对这个 Spring 的理解不够,出现了把 实现了同一个接口的不同子类注入到一个Map中,使用时再从其中获取的行为,最要命的是,这个 map 的key 不是那些子类的名称,还写了很多 switch case …… 😶 来获取
image-20211112221843944
其实我们直接用 ApplicationContext 的 getBean 就可以获取到了 🐖
更新,插入操作
在更新或者插入成功后,还要将这些数据写到 Log 表 …… 😑
真是太魔幻了…… 再坚持下就快到吐槽环节了😂
这里我们要考虑一个问题了—— 插入数据时,ID 是插入数据前就有的,还是插入数据后才有的?🐷
在项目中我们使用的是这个 Oracle,借助它的 Sequence,我们可以先获取这个 ID (select XX_SEQ.nextval from dual),再设置到这个对象中去,然后再插入 DB 中 。
而在使用 MySQL 时,我们一般都是通过数据库的自增ID,当数据插入后,再从这个对象中获取到这个 ID 的。
这也决定了我是在 AOP 的 Before 中记录下这些 ID ,还是在 AfterReturning 中去获取的。
其实一开始我是直接在 Before 中去记录的,后来考虑到这种情况后,才把它移到 AfterReturning 中去的,毕竟不管你先生成还是后生成,我都可以后获取,而且第二种模式兼容第一种模式 🐷
更新的话也有两种情况:(一)根据主键更新 ,这种最简单,我们直接根据主键查出之前的数据即可。(二)根据其他条件更新,这里我们自定义获取主键的方法以便复用上面的方法。
一般情况下,我们可以自动去获取这个 id,有些情况比较复杂的,就提供这个手动模式,自己调用 ThreadLocal 并耦合到代码中。
最后使用 Spring 的工具 BeanUtils ,将数据拷贝到日志对象中 BeanUtils.copyProperties(model, logModel); ,再通过 BaseMapper 的 insert 方法,将数据一条条插入到 Log表。
到此,就完成了这个特殊的日志模块的优化了。
image-20211112222053399
这个模块也为团队节省了 N 倍的开发时间,减少了很多冗余,无效的代码,也提高了这个代码的可维护性,受到同事的肯定当时 哈哈 😝 而且好像从这时候开始,老大找我做了一些通用模块的开发,比如 模板,邮件,Excel 等,有机会再来和小伙伴们分享下~ 😄。
吐槽
终于来到这里了,说实话,我到现在都觉得这个日志模块很 “特别” 🐷,因为这个日志模块不像我平时了解过的那些,比如:
-
请求的入参,出参
-
业务
-
异常
-
JVM,Nginx,Tomcat 等等
而且奇怪的点还不是写入 DB 这个操作,而是针对大量的表做这备份的这个行为,比如 有这个表A,然后我还要创建相应的日志表 LOG_A,而且只要你修改或者新增数据到表A,那么 LOG_A 会将你更改后的 A 数据记录下来,删除的话,会将你删除前的A数据记录下来,删除成功后才记录到这个 LOG_A 。
而且这个 LOG_A 就比表A 多了几个字段,比如这个操作行为( CRUD 中 的 CUD)和 操作ID (即请求ID)。
这…… 简直就是究极备份了🐖 (我实在想不出哪个词来形容了 哈哈 我只能说太慎重了!和 慎重勇者 的主角有得一比)
这是我新的感悟 哈哈。
还记得那时的我十分抗拒把这个东西搬到新项目中,因为我觉得它很多余,这不就是把数据又写了一遍到另一个表中,而且我觉得用网上的例子就可以了啦,就记录下数据从什么修改成什么就好了,要那么多干嘛🤨。
image-20211112222404482
我当时也憋不住,就向老大表达了我的疑惑,老大和我解释说这个日志模块是为了方便找 bug,找出哪些数据是有问题的,写这篇文章的时候我还特意再去请教了一下,他说他们的老项目用到了,但是具体怎么用也没说 🐖
为了搞清楚这个东西的作用,额 我已经问了三个项目组的同事了,终于有个同事使用到了,就是说有一次数据出了问题,看代码看了好久都没有觉得哪里有问题,后来就是靠着这个请求id,去db找那批数据出来分析,才找到问题的。
不过我听完还是觉得一言难尽,什么bug 连 debug 都不能找出来,得靠分析这批数据去找出来🙃 我甚至觉得它负作用更多…… 😮
坑
印象中在重写这个模块时,遇到一个很有意思的问题 如下 👇
@Mapper
public interface XXXMapper extends BaseMapper {
@Override
@MethodLog(method = TableAction.D,
model = XXX.class,
logModel = LogXXX.class,
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!
%;" />
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
[外链图片转存中…(img-LoEOBOIP-1712092224148)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》,点击传送门即可获取!