spring_boot全局事务设置
一、简介:
在我们平常开发中,常需要用到事务。例如账单等数据,一旦出现错误,需要将之前的插入的数据进行回归。这里事务主分为2种,一种是直接在对应的逻辑上添加@Transactional注解即可,但是对于异常需要@Transactional(rollbackFor = {Exception.class}) 捕获回滚。这个才可以,但是这个有个缺点,就是需要在所有的service层上都加才行。所以是极为不方便的,所以我们这里用全局设置,给所有的service层加上事务,这样不用一个个加了
二、逻辑:
这里我们可以通过spring AOP 的方式去实现,及扫码所有文件,根据我们设定的模糊路径和匹配的模糊java名称进行设置,对其中的模糊方法名,进行特别的事务级别及规定进行特殊设定。
三、实现:
这里我们直接上代码:
1.需要先引入对应的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
2.编写配置文件。
package org.springcrazy.common.config;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.interceptor.*;
import java.util.Collections;
/**
* 全局事务统一配置
*
*/
@Slf4j
@Aspect
@Component
public class TransactionAdviceConfig {
public static final String aop_pointcut_expression = "execution(* org.springcrazy.modules.*.service.impl.*.*(..))";
@Autowired
PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
//增删改使用PROPAGATION_REQUIRED 当前有事务则加入该事务,没有事务则创建事务
RuleBasedTransactionAttribute txAttr_REQUIRED = new RuleBasedTransactionAttribute();
//事务回滚机制
txAttr_REQUIRED.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//事务隔离机制
txAttr_REQUIRED.setIsolationLevel(Isolation.DEFAULT.value());
//读使用PROPAGATION_SUPPORTS 当前有事务则加入该事务,没有事务则以非实物方式运行
DefaultTransactionAttribute txAttr_SUPPORTS_READONLY = new DefaultTransactionAttribute();
//事务回滚机制
txAttr_SUPPORTS_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
//事务隔离机制
txAttr_SUPPORTS_READONLY.setIsolationLevel(Isolation.DEFAULT.value());
txAttr_SUPPORTS_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
//这里添加方法的事务运行机制 名字以add开通的方法走这个
source.addTransactionalMethod("add*", txAttr_REQUIRED);
//设置读的方法的事务运行机制 名字以get开通的方法走这个
source.addTransactionalMethod("get*", txAttr_SUPPORTS_READONLY);
//设置其他方法的事务运行机制
source.addTransactionalMethod("*", txAttr_SUPPORTS_READONLY);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
//加入扫码文件的规则
pointcut.setExpression(aop_pointcut_expression);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
这里需要注意几个点
1.这里的文件路径,一定要指定到继承service的Impl的位置。
如果您的serviceImpl没有依照一定的规则进行创建。则就无法进行全部设定。例如我的都是在org.springcrazy.modules.XX.service.impl下。*号代表所有名称。*(..)代表所有的有参或无参的方法。
则我的扫码路径则为
* org.springcrazy.modules.*.service.impl.*.*(..)
注意这里的的第一个*与后面的文件名一定之间要有空格。
spring在TransactionDefinition中规定了7种类型的事务行为。规定了具体的事务需要怎么进行调用
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
这里我们增删改都用的是PROPAGATION_REQUIRED这个最常用的。而查询我们用PROPAGATION_SUPPORTS。
之后我们就可以测试。例如写一个批量添加的方法。对库进行操作。正常情况没有事务时,如果批量操作中某个报错。则之前添加的不回回滚,但是加上事务则可进行回滚操作,但是有些值例如主键,大部分主键都带有自增,如果出现回滚,但是自增值不会进行回滚的。也就是我们加10个值,第5个报错了。没有事务的则数据会停留子第四个插入的。自增值为5。加入事务后,数据一个都不会插入,但是自增值依旧停留在5。