一前言
在操作数据库的时候,我们经常对一个service层进行事务设置,在springmvc中都是配置在xml文件中,在springboot中想要进行统一事务配置,在查找了大量的资料后,发现有一个很好,很久之前就用过了,这次加上自己的理解贴出来。
二、基于注解形式的统一事务管理
1)代码:
/**
*
*/
package com.zlc.config;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
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.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* @Description: 基于注解的方式的统一事物处理
* @Create Date: 2017年9月30日下午8:47:07
* @Version: V1.00
* @Author: 追到乌云的尽头找太阳(Jacob)
*/
@Aspect
@Configuration
public class TxAdviceInterceptor {
// 超时时间 单位秒
private static final int TX_METHOD_TIMEOUT = 5;
// 面向切面,通过切面到service层的操作,进行事务统一管理
// 包名记得一定要改为自己的,不然不生效
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.zlc.service.*.*(..))";
// service 包下的所有类,所有方法,如果service下还有子包,且这种配置没生效,则可以改为 com.zlc.service.*.*.*(..))
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
// 只读事务,不做更新操作
RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
readOnlyTx.setReadOnly(true);
readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
// 当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务
RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
requiredTx.setRollbackRules(
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
requiredTx.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>();
// 这里是设置什么样的操作对应的事务级别 比如getXXX方法,就是只读
// 需要和自己的service方法对应上
txMap.put("add*", requiredTx);
txMap.put("save*", requiredTx);
txMap.put("insert*", requiredTx);
txMap.put("update*", requiredTx);
txMap.put("delete*", requiredTx);
txMap.put("get*", readOnlyTx);
txMap.put("query*", readOnlyTx);
source.setNameMap( txMap );
TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
return txAdvice;
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
三、说明
通过注解形式的事务统一管理,有方便之处就是省去配置文件那种略显乱的方式,而且通过注解形式编程貌似现在也是一个趋势。缺点也很明显,就是东西写死在代码里了。
2)当上面的面向切面事务管理生效后,比如说你在使用spring data JPA的delete或者uodate方法时,有时会报错,然后查看执行的删除SQL语句,开头居然是 select,这种就是没有事务,一种解决办法就是 加上 @Transactional 以及@Modify这两个注解才能让删除是真的删除。