Spring Boot开启声明式事务

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 {
    // 没有开启事务(或者没有配置成功)
}

调试的时候可以看到事务状态对象如下图:

Spring Boot开启声明式事务

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配置了。

给TA打赏
共{{data.count}}人
人已打赏
运维

SpringBoot日志配置

2024-11-19 10:36:22

运维

注册中心Nacos安装使用

2024-11-19 10:36:25

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索