本系列文章旨在利用spring提供的后门,优雅的实现自定义逻辑,掌握这些spring的高阶/装逼/实用技巧后,能迅速提升代码逼格,拉开与同事间的距离

某天,后台小张被领导交待了一个任务。

领导:小张啊,业务那边想要统计下我们这边每天注册商户成功和失败的数量,你看看怎么给他弄下这个功能

小张听了心想,我弄一张商户注册记录表,在注册商户完成后,往里面插入数据不就行了吗!

便马上接下了这个需求。

5分钟后,小张建好了商户注册记录表,他打开idea,找到商户service的注册方法。

在return前加上了如下代码

完事搞定,就在小张准备去提交代码时,猛然惊觉,假如方法内有抛出异常(业务异常或系统异常),这种做法就不生效了!!!然后马上进行了第二版的修改

小张这次心想:我再套一层,然后对注册方法进行try catch,捕获到异常就插入失败记录,这总行了吧。

就在小张准备再次提交代码之时,忽然感受到了八阿哥(bug)的召唤

八阿哥:小伙子,你这个插入日志的mapper方法要是报错了,注册商户那会回滚的啊!!!

小张顿时感激涕零,遵从仙人的指点,再次调整了代码

这次是把插入日志封装成一个方法,并在里面try catch,这样就不会影响注册商户的逻辑了!

终于,小张提交了代码并通知了领导需求已开发完成。


在需求上线前,领导都会例行review下代码,在看了小张的代码实现后,给小张提了点意见。

领导:小张啊,虽然你这个实现没什么问题,但是搞得有点复杂,本来registCustomer方法里是注册商户的逻辑,现在被你弄到doRegistCustomer方法里了,增加了一些后期维护成本。还有你原本应该是想要在registCustomer方法执行完后再去插入日志的吧,因为调用这个方法的地方太多,在调用方那加插入日志的逻辑改动太大了,才会想着弄个doRegistCustomer方法的吧。

小张老脸一红,心想领导不愧是领导,竟把自己的实现想法说出了个七七八八,不好意思的点了点头。

领导:其实你可以去搜下TransactionSynchronizationManager.registerSynchronization的用法,当registCustomer方法事务进行中时,可以通过这个方法插入一些业务逻辑,你换成用这个实现吧。


review代码环节就这样结束了,小张赶忙去搜索了下TransactionSynchronizationManager.registerSynchronization,发现这是spring事务提供的注册回调接口的方法。

在事务注解方法中,通过该方法注册事务回调接口后,spring会在事务提交/回滚前后调用注册的回调接口的对应方法,方法如下

  1. suspend:在spring开启新事务,获取connection之前会调用(未执行registCustomer)
  2. resume:开启新事务失败时会调用(未执行registCustomer)
  3. flush:没调用
  4. beforeCommit:事务提交前会调用(已执行registCustomer)
  5. beforeCompletion:事务提交前会调用,在beforeCommit之后(已执行registCustomer)
  6. afterCommit:事务提交后会调用(已执行registCustomer)
  7. afterCompletion:事务提交后会调用,在afterCommit之后(已执行registCustomer)

在了解TransactionSynchronization的用法后,小张把代码调整为了

如果status为_STATUS_COMMITTED_表示方法正常,事务已提交,需要插入成功记录,如果status为_STATUS_ROLLED_BACK_则说明发生了异常,事务已回滚,则插入失败记录,完美!!!

想知道其原理需要了解spring事务源码实现,可查阅该篇文章

小张再次申请领导review代码后,领导给了小张一个大大的赞,其他同事看了代码后,都惊呼高端操作!!!(稍微写的有点夸张)小张表示,自己会多多学习spring相关知识,将代码写的更优雅(多看看本系列文章就够了!!!)


本文转自 https://zhuanlan.zhihu.com/p/375854755,如有侵权,请联系删除。