概述
sql或数据库的操作交给第三方框架封装(如mybatis等)。事务的回滚提交操作是通过connection完成的,如何保证spring封装mybatis在执行一系列mapper操作时使用的connection是同一个,这是spring执行事务的关键。spring中事务管理器“DataSourceTransactionManager”管理的本质上管理的就是连接。
spring事务管理包含两种情况:
- 编程式事务
- 声明式事务(包括基于注解@Transactional(配合切面)和tx+aop)
编程式事务
编程式事务TransactionTemplate需要手动在代码中处理事务,一般不推荐使用。使用过程1、配置transactionmanager
<!--
2.配置transactionTemplate
<!--
3.演示demo
@Autowired
声明式事务
1.配置
<!--
2.使用
@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上(由 Spring AOP 的本质决定)。
3.演示demo
@Transactional
注意:
1.接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。
2.接口中异常(运行时异常)被捕获而没有被抛出。默认配置下,spring 只有在抛出的异常为运行时 unchecked 异常时才回滚该事务,也就是抛出的异常为RuntimeException 的子类(Errors也会导致事务回滚),而抛出 checked 异常则不会导致事务回滚 。可通过@Transactional rollbackFor进行配置。
3.多线程下事务管理因为线程不属于 spring 托管,事务管理信息存储在threadlocal中,对于其他线程不可见,故线程不能够默认使用 spring 的事务。(添加 @Asny+@Transactional可以实现新线程调用方法有事务)
也不能获取spring 注入的 bean 。在被 spring 声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,不会回滚线程中调用方法的事务。
4.父类的声明的 @Transactional 会对子类的所有方法进行事务增强;
子类覆盖重写父类方式可覆盖其 @Transactional 中的声明配置。
5. 注意当方法加上synchronized时,由于锁的作用范围比事务的作用范围小,因此应该修改锁的作用范围,保证锁的范围比事务的范围大即可。
6 .在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。 原因:Java代理不能代理类,只能代理接口。 Spring通过AopProxy接口,抽象了这两种实现,如下图methodB没有被AopProxy通知到。解决办法:分开成两个类。
@Transactional原理
@Transactional 实质是使用了 JDBC 的事务来进行事务控制的,基于AOP实现。
1) 事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入某个与 DataSourceTransactionManager 相关的某处容器中。在接下来的整个事务中,客户代码都应该使用该 connection 连接数据库, 执行所有数据库命令。
[不使用该 connection 连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚]
(物理连接 connection 逻辑上新建一个会话session;DataSource 与 TransactionManager 配置相同的数据源)
2) 事务结束时,回滚在第1步骤中得到的代理 connection 对象上执行的数据库命令,
然后关闭该代理 connection 对象。
参数