我发现很多开源的springBoot项目,使用事务都是 直接使用 事务注解。并没有配置全局事务的。
其实目前现在不是新人程序员就以为 事务就只能靠加注解来控制了。根本没听说过全局事务配置。
网上很多全局事务其实都是不够好的。都是抄来抄去的。真的不知道能不能用。
其实这样很不好的。
- 写代码的时候如果漏了加上事务注解,那异常不回滚太可怕了
- 如果写代码的时候都需要手动加上注解,多费事啊。配置全局事务注解多省事。
配置代码
package com.door.config;
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.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/** 全局事务控制,防止漏加 事务注解,也就是说开发中可以不用加事务注解了 */
@Configuration
@Aspect
public class TransactionConfig {
private static final int TX_METHOD_TIMEOUT = 60;
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.door..service..*(..))";
@Autowired private PlatformTransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
readOnly.setReadOnly(true);
readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 禁止使用这种 。这种会导致 只读事务不生效的。而且 可以 在代码里面 提交事务的
// readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
required.setRollbackRules(
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 单位是 秒
required.setTimeout(TX_METHOD_TIMEOUT);
Map<String, TransactionAttribute> txMap = new HashMap<>(50);
txMap.put("add*", required);
txMap.put("save*", required);
txMap.put("insert*", required);
txMap.put("update*", required);
txMap.put("delete*", required);
txMap.put("create*", required);
txMap.put("init*", required);
txMap.put("submit*", required);
txMap.put("remove*", required);
txMap.put("edit*", required);
txMap.put("modify*", required);
txMap.put("batch*", required);
txMap.put("mass*", required);
txMap.put("handle*", required);
txMap.put("exec*", required);
txMap.put("import*", required);
txMap.put("set*", required);
txMap.put("get*", readOnly);
txMap.put("select*", readOnly);
txMap.put("list*", readOnly);
txMap.put("query*", readOnly);
txMap.put("find*", readOnly);
txMap.put("count*", readOnly);
txMap.put("page*", readOnly);
txMap.put("all*", readOnly);
txMap.put("*", readOnly);
source.setNameMap(txMap);
return new TransactionInterceptor(transactionManager, source);
}
// @Bean 这种方式不够好,不能配置回滚异常。 其实和上面的方式 的原理是一样的。
// public TransactionInterceptor txAdvice() {
//
// DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
// txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// txAttr_REQUIRED.setTimeout(TX_METHOD_TIMEOUT);
//
// DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
// txAttr_REQUIRED_READONLY.setPropagationBehavior(
// TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
// txAttr_REQUIRED_READONLY.setReadOnly(true);
//
// NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
// source.addTransactionalMethod("add*", txAttr_REQUIRED);
// source.addTransactionalMethod("save*", txAttr_REQUIRED);
// source.addTransactionalMethod("delete*", txAttr_REQUIRED);
// source.addTransactionalMethod("update*", txAttr_REQUIRED);
// source.addTransactionalMethod("exec*", txAttr_REQUIRED);
// source.addTransactionalMethod("set*", txAttr_REQUIRED);
//
// // source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
// // source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
// // source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
// // source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
// // source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
// source.addTransactionalMethod("*", txAttr_REQUIRED_READONLY);
//
//
//
// return new TransactionInterceptor(transactionManager, source);
// }
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
TransactionDefinition.PROPAGATION_NOT_SUPPORTED 不要配置
以前同事就是这样配置的,之前一直都没有注意到,今天测试 只读事务的时候,才发现根本没有起作用。
还是可以在 方法里面执行 写数据库操作的,而且并没有事务控制!!
source.setNameMap(txMap); 与 addTransactionalMethod 是一样的原理
source.setNameMap(txMap); 的源码 就是 循环调用 addTransactionalMethod 方法
搜索很多都是 DefaultTransactionAttribute 这样的代码,并不能定义Execption异常类型回滚
xml 全局事务配置
没有使用spring boot 开发之前的老项目,基本都是 使用 xml 进行配置全局事务拦截的
<!--事务配置示例-->
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.skg.crm.*.domain..*(..)) " />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--对于oracle来说 read-only="true" 没什么效果,
配置回滚异常是为了防止 不小心使用了操作数据出现异常没有回滚。
如果方法里面没有操作数据而出现异常,配置回滚没有影响 -->
<tx:method name="get*" read-only="true" rollback-for="java.lang.Exception" />
<tx:method name="is*" read-only="true" rollback-for="java.lang.Exception" />
<tx:method name="find*" read-only="true" rollback-for="java.lang.Exception" />
<tx:method name="query*" read-only="true" rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="REQUIRED" read-only="false" isolation="DEFAULT" rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<!-- 开启事务控制的注解支持,proxy-target-class="true"类代理适用范围广 -->
<!-- order 一般是不用配置的,如果aop xml 配置了事务了,代码又使用了事务的注解,那么以代码的注解为主。
带上order 是防止以后代码上有其他自定义的AOP 而影响了事务注解的aop的异常的事务回滚,默认事务注解的aop的优先级最低。
加上也是为了明确告诉spirng 声明式事务注解优先级最高。
-->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" order="200"/>
参考
来源:oschina
链接:https://my.oschina.net/ouminzy/blog/4713334