本篇文章只涉及 spring 事务的配置, 不进行事务的介绍.
spring 通过 PlatformTransactionManager 接口作为事务管理器来进行事务的管理, 它本身并不进行事务的创建以及相关操作, 它就相当于事务管理的容器, 里面放的是事务. 事务使用有编程式事务和声明式事务, 现在一般情况下都是使用声明式事务.
声明式事务使用方法:
1, 在配置的 xml 文件中使用 AOP 模式来进行事务声明, 如下所示
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <tx:advice id="txAdvice" transaction-manager="transactionManager">
- <tx:attributes>
- <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <aop:pointcut id="interceptorPointCut"
- expression="execution(* com.test.service.impl.*.*(..))" />
- <aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCut" />
- </aop:config>
2, 使用注解形式进行事务声明, 如下所示:
第一步: 在 xml 配置文件中加入如下配置
- <!-- 启动声明式注解 -->
- <tx:annotation-driven transaction-manager="transactionManager" />
或者在被 @configuration 注解注释的类上添加 @EnableTransactionManagement 注解
第二步: 在需要添加事务的类或方法上添加 @Transactional 注解, 注解可以设置 value(用来设置数据源),transactionManager(同 value 作用相同),propagation(设置事务的传播行为, 使用枚举 Propagation 来选择值, 默认是 REQUIRED),isolation(设置事务的隔离机制, 使用枚举 Isolation 来选择值, 默认是底层数据库支持的事务的默认隔离机制),timeout(设置事务的超时时间, 可以使用 TransactionDefinition 接口提供的值, 默认值为 - 1),readOnly(布尔值, 设置事务为只允许读, 不进行修改操作, 如果是只有读的操作可以设置为 true, 官方解释设置为 true 时, 会在运行时进行相应的优化, 但是并不能保证进行修改操作会失败),rollbackFor(设置进行事务回滚的异常类类型),rollbackForClassName(设置进行事务回滚的异常类类名),noRollbackFor(设置不会进行事务回滚的异常类类型),noRollbackForClassName(设置不会进行事务回滚的异常类类名)
即使没有设置 rollbackFor,rollbackForClassName 的值, spring 框架在我们调用的方法发生运行时异常的时候会进行事务回滚操作.
3, 利用 AOP 的 around 类型的 advice 进行事务声明, 如下所示
- @Aspect
- @Component
- public class TransactionalAop {
- @Autowired
- PlatformTransactionManager transactionManager;
- @Around("execution(* com.test.service.impl.*.*(..))")
- public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {// // 利用 spring 框架提供的事务模板类进行事务操作
- // TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
- // transactionTemplate.execute((status) -> {
- // Object result = null;
- // try {
- // result = pjp.proceed();
- // } catch (Throwable e) {
- // if (e instanceof RuntimeException) {
- // throw (RuntimeException)e;
- // }
- // if (e instanceof Error) {
- // throw (Error)e;
- // }
- // throw new RuntimeException(e);
- // }
- // return result;
- // });
- // 手动创建事务 (同时开启事务) 并根据方法调用结果进行事务回滚或者提交
- TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());
- try {
- pjp.proceed();
- } catch (Throwable e) {
- transactionManager.rollback(transaction);
- throw e;
- }
- transactionManager.commit(transaction);
- }
- }
如上所示, 我们可以利用 spring 提供的 TransactionTemplate 类来进行事务的相关操作, 但是这里使用有个小缺陷, 就是 execute(TransactionCallback<T> action)方法里的参数 action 中的 doInTransaction(TransactionStatus status)方法没有显式抛出异常, 所以我们只能在 doInTransaction(TransactionStatus status)方法中抛出运行时异常或 Error 来进行事务的回滚. 如果是自己手动进行事务开启, 提交, 回滚就不会存在这个问题, 如上所示, 利用 PlatformTransactionManager 接口的 getTransaction(@Nullable TransactionDefinition definition)方法来进行事务的开启, 最后根据方法的执行结果来进行事务提交或回滚操作.
综合:
第一种方法是老式的 xml 配置文件进行事务配置的方法, 需要用到 xml 配置文件, 在如今 springboot 肆意横行的时代(springboot 允许我们加载 xml 配置文件, 但是如果还在使用 xml 配置文件不是又回去了吗?!), 这种配置方式已经算是落伍了.
第二种方法是基于注解进行事务配置的方法, 算是比较方便. 优点是: 事务管理的粒度比较细,@Transactional 既可以用在类上也可以用在方法上; 缺点: 至少每个业务逻辑的类都要用到 @Transactional 注解.
第三种方法是利用 aop 的动态代理原理, 在方法调用之前进行事务开启, 根据方法执行结果来进行事务的相关操作. 优点: 事务统一管理, 不在需要每个类或方法上添加 @Transactional 注解; 缺点: 事务管理的粒度比较粗.
来源: https://www.cnblogs.com/zzw-blog/p/9708822.html