本篇文章只涉及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注解;缺点:事务管理的粒度比较粗。