深入理解spring事务原理,手动实现事务提交和回滚

1.其实最开始不知道怎么写,后来想想,想要把一件事情,用“人话”讲明白,就需要从最简单的开始,再逐步加入难度。
2.为什么,非要写代码呢?有两点:第一:验证自己的思想和逻辑,第二:锻炼自己的编码能力。
3.搭建项目的时候,遇到来AOP失效的问题。解决方法在:springboot中aop切面失效,导致注解不起作用
4.为什么要自己实现,而不用框架呢?只有这样,才能真正领悟框架的底层和精髓。

NO1.框架自动提交事务与异常回滚

先讲一下场景吧,我要删除数据库中的一条记录,那么删除的结果有两种,一种是删除成功,提交事务,另外一种是执行删除的过程中发生异常,回滚事务。
但是,在实际开发过程中,我们从来不直接操作数据库,而是通过ORM框架来操作或者Java相关框架来干这个活!
今天也不例外,我们用springboot + jdbcTemplate来实现这个操作的过程。

在这里插入图片描述
这段代码,我想大家都认识,并且也经常写,但是,用的不是jdbcTemplate,而是调用mybatis。效果一样,为来快速实现,我们用jdbcTemplate实现。

需要注意的地方

@Transactional中的rollbackFor必须加上,否则回滚不生效。
如果,你不信,你可以自己写代码试试

NO2.控制框架的提交和事务回滚

第一个问题:我们用来jdbcTemplate,我们是否可以控制事务的提交和回滚吗?

答案是肯定的,那需要怎么做呢?

在这里插入图片描述
既然,我们要控制事务的提交,那么我们就需要拿到sql链接,也就是connection.
那么,connection从哪里获取呢?当然,是从DataSource中获取了。

第二个问题:如果,不用DataSource,怎么获取链接呢?

在Springboot中,因为配置了DataSource,所以,DataSource替我们去获取了数据库的connection。如果,没有DataSource,我们怎么获取connection呢?这个应该是一个最基础的了,就是通过JDBC去获取connection。在最初学习Java的时候,我们不用任何ORM框架操作数据库,就是用JDBC实现的。
其实,市面上的ORM框架也都是封装了JDBC的功能,并实现了sql解析、参数映射、结果映射等功能,为了就是简化开发人员的工作量,提高开发人员的工作效率。
但是,这也导致越来越多的开发人员,根本不知道JDBC的存在了。
只是会用了工具,不知道工具是怎么做的。一旦,工具出了问题,根本不知道怎么修理。

NO3.AOP+注解实现事务的提交和回滚

第三个问题:从上面的两段代码,你能总结出上面规律?

第一个,是通过Springboot的jdbcTemplate来实现事务的操作,我只要懂得API就可以了。
第二个,想看看框架的执行流程是怎么样子的,所以,我来手动控制了事务的提交和回滚。
第三个,分析第二段代码,我发现几个我一直很疑惑的问题:

  • 事务提交,是怎么由框架来提交的,原来就是框架替我们做来获取链接,并且设置不自动提交,在我们的业务代码执行完成以后,再提交的。
  • 事务回滚,就是在我们业务代码执行出现异常的时候,进行事务回滚的。
  • 是不是,突然间豁然开朗,就是这么一个思想,我们只需要关心业务代码,系统或者框架来帮你操作事务。

第四个问题:既然,知道了思想,那么让我们自己来实现,你会怎么样实现呢?

这种思想和动态代理是不是很像,我们要做的就是给业务类的方法增强。增强的部分就是获取数据库链接,实现事务的提交和回滚。
在使用Spring开发的过程中,我们可以用Spring的aop来实现这个功能。

在这里插入图片描述

代码并不多,我讲一下我的整个思路和关键类

  • 我封装了一个MyTemplate,主要用于获取connection和执行sql语句
    在这里插入图片描述
  • 我定义了一个注解@MyTransactional,用于切面类MyTransactionalAop使用
    在这里插入图片描述

第五个问题:两条sql语句或者多条sql语句,如何实现事务的提交和回滚呢?

答案是,必须在一个connection中执行,才能进行事务的操作。

第六个问题:如何才能保证执sql语句的connection是同一个呢?

这个就用到了ThreadLocal,其中的知识点是线程封闭,这里就不展开说了,大家自己去了解一下吧!

第七个问题:spring中@Transactional的原理,能不能讲一下?

你们觉得,注解的原理是什么?我觉得,@Transactional只是注解,真正调用的地方是获取注解中的相关配置属性,然后在Connection提交事务的时候来做业务判断而已。如何获取,在Spring中最经典的就是通过AOP+反射。

NO4.spring事务源码解读

TransactionSynchronizationManager(事务管理器 )

看源码速记方法,类名#方法名–操作
一般看源码的时候,真正操作的地方,都是以doxxxx开头的。

DataSourceUtils#getConnection–获取链接
DataSourceUtils#doGetConnection–获取链接操作,从TransactionSynchronizationManager中获取
TransactionSynchronizationManager#getResource–获取资源
TransactionSynchronizationManager#doGetResource–从resources获取资源值,resources是一个ThreadLocal

TransactionAttributeSource(事务注解属性资源)

TransactionAttributeSourceAdvisor#transactionInterceptor
TransactionAttributeSourcePointcut#TransactionAttributeSourceClassFilter#matches
AnnotationTransactionAttributeSource#isCandidateClass–解析并设置属性
SpringTransactionAnnotationParser#isCandidateClass–解析注解策略

总结:

通过上面几个简单的类,我们就实现了事务的控制。其实,实现没那么复杂,重要的思想。通过阅读源码,我们知道了事务注解,是通过AOP来完成的。是不是和我实现的思想是一样的?

发布了80 篇原创文章 · 获赞 42 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/lvhonglei1987/article/details/104636786