Spring Boot开启声明式事务
在以前早期的Spring使用xml方式的时候,配置声明式事务通常用xml方式,使用Spring boot开始,xml基本算是淘汰了,因此怎么配置声明式事务呢?当然还是可以用xml或者JavaConfig方式。
开启Spring Boot事务(注解式)
要开启Spring Boot事务比较简单,在一个配置类中使用一个注解就可以了
@EnableTransactionManagement
开启后可以用@Transactional
注解给方法增加事务即可
声明式事务配置方式就不太一样了,不需要每个方法上去配置,可以使用aspectj
语法表达式指定包下面的类根据方法名字前缀配置,只要名字匹配就可以实现事务,相对来说比较方便。
execution (* com..service..*.*(..))
判断事务状态
如何判断一个方法执行的时候是否在Spring的事务中呢?其实Spring启动一个事务之后,会把相关信息写入到ThreadLocal
中,然后Spring提供一个工具类(TransactionSynchronizationManager
),可以查看事务执行过程中的状态等信息。
if (TransactionSynchronizationManager.isActualTransactionActive()) {
TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
// 查看状态信息
} else {
// 没有开启事务(或者没有配置成功)
}
调试的时候可以看到事务状态对象如下图:
XML方式配置声明式事务
在spring boot项目中,使用@EnableTransactionManagement
开启了事务之后,事务管理器已经存在了,然后只需要配置事务切面即可,spring boot也是支持xml方式配置的,可以编写好xml(我这起名叫spring-tx.xml
),然后使用注解引入。
@ImportResource("classpath:spring-tx.xml")
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 自动映射事务, spring boot项目中@EnableTransactionManagement已经有transactionManager,引用即可 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="remove*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="create*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="mark*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true" />
<tx:method name="query*" read-only="true" />
<tx:method name="list*" read-only="true" />
<tx:method name="count*" read-only="true" />
<tx:method name="page*" read-only="true" />
<tx:method name="find*" read-only="true" />
<tx:method name="load*" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:aspectj-autoproxy/>
<aop:config proxy-target-class="true">
<!-- 切入点 -->
<aop:pointcut id="interceptorPointCuts" expression="execution (* com..service..*.*(..))"/>
<!-- 通知 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" order="200"/>
</aop:config>
</beans>
JavaConfig配置声明式事务
其实JavaConfig方式相对比较简单一点,只需要写一个配置类即可:
@Configuration
public class GlobalTransactionConfig {
/**
* 注入已经存在的事务管理器
*/
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
// 开启事务方法
TransactionAttribute requiredTransaction = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED);
NameMatchTransactionAttributeSource nameMatchSource = new NameMatchTransactionAttributeSource();
nameMatchSource.addTransactionalMethod("save*", requiredTransaction);
nameMatchSource.addTransactionalMethod("delete*", requiredTransaction);
nameMatchSource.addTransactionalMethod("remove*", requiredTransaction);
nameMatchSource.addTransactionalMethod("update*", requiredTransaction);
nameMatchSource.addTransactionalMethod("add*", requiredTransaction);
nameMatchSource.addTransactionalMethod("create*", requiredTransaction);
nameMatchSource.addTransactionalMethod("insert*", requiredTransaction);
nameMatchSource.addTransactionalMethod("mark*", requiredTransaction);
// ReadOnly事务方法
DefaultTransactionAttribute readonlyTransaction = new DefaultTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED);
readonlyTransaction.setReadOnly(true);
nameMatchSource.addTransactionalMethod("get*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("query*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("list*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("count*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("page*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("find*", readonlyTransaction);
nameMatchSource.addTransactionalMethod("load*", readonlyTransaction);
return new TransactionInterceptor(transactionManager, nameMatchSource);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution (* com..service..*.*(..))");
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
声明式事务依赖
只要使用了声明式事务,由于使用了切面(aop)功能,就必须依赖spring-aop
项目和aspectjweaver
项目,否则会报错,spring boot项目直接引入spring-boot-starter-aop
即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
总结
其实spring boot项目配置声明式事务,无论使用xml还是注解方式,都是使用aop方式配置拦截方法执行即可。
实际项目中可以考虑使用注解会更加方便,而且目前spring项目都是去xml化,xml注定是被抛弃的,新项目基本看不到xml配置了。