一把再SpringBoot中拿aop做全局事务时候代码大致都是如下:
@SpringBootConfiguration
@EnableTransactionManagement
@EnableAspectJAutoProxy
@MapperScan("xxx.server.dao.mapper")
public class JdbcConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution (* xxx.server.service.impl.*.*(..))";
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("datasourceTxAdvice")
public TransactionInterceptor txAdvice(DataSourceTransactionManager transactionManager) {
DefaultTransactionAttribute txAttrRequired = new DefaultTransactionAttribute();
txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttrRequiredReadonly = new DefaultTransactionAttribute();
txAttrRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttrRequiredReadonly.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("save*", txAttrRequired);
source.addTransactionalMethod("delete*", txAttrRequired);
source.addTransactionalMethod("update*", txAttrRequired);
// ...
source.addTransactionalMethod("*", txAttrRequiredReadonly);
final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionManager(transactionManager);
transactionInterceptor.setTransactionAttributeSource(source);
return transactionInterceptor;
}
@Bean
public Advisor adviceAdvisor(
@Qualifier("datasourceTxAdvice") TransactionInterceptor transactionInterceptor) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor);
}
}
这个配置的意思是只有service层的实现类中的方法会开启事务,且开启事务时候允许嵌套事务,save/delete/update开头的方法不是只读事务,剩下的方法都是只读事务。这里用的是默认的DefaultTransactionAttribute,这里边判断是不是要回滚的标志就是异常是不是RuntimeException或者Error。
具体代码如下:
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
// 省略部分代码
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
// 省略部分代码
}
Spring中事务实现的核心代码再org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction方法中。
这个TransactionAspectSupport类中方法最终会调用TransactionAttribute#rollbackOn方法来确定要不要回滚。
所以要想实现部分异常下的不回滚,实现关键也在这里。如下是我实现以后的代码:
// 自定义不回滚事务的异常类
public class NoRollbackException extends RuntimeException {
public NoRollbackException() {
super();
}
public NoRollbackException(String message) {
super(message);
}
public NoRollbackException(String message, Throwable cause) {
super(message, cause);
}
public NoRollbackException(Throwable cause) {
super(cause);
}
}
@SpringBootConfiguration
@EnableTransactionManagement
@EnableAspectJAutoProxy
@MapperScan("xxx.server.dao.mapper")
public class JdbcConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution (* xxx.server.service.impl.*.*(..))";
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean("datasourceTxAdvice")
public TransactionInterceptor txAdvice(DataSourceTransactionManager transactionManager) {
DefaultTransactionAttribute txAttrRequired = new CustomRuleBasedTransactionAttribute();
txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttrRequiredReadonly = new CustomRuleBasedTransactionAttribute();
txAttrRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttrRequiredReadonly.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("save*", txAttrRequired);
source.addTransactionalMethod("delete*", txAttrRequired);
source.addTransactionalMethod("update*", txAttrRequired);
// ...
source.addTransactionalMethod("*", txAttrRequiredReadonly);
final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
transactionInterceptor.setTransactionManager(transactionManager);
transactionInterceptor.setTransactionAttributeSource(source);
return transactionInterceptor;
}
@Bean
public Advisor adviceAdvisor(
@Qualifier("datasourceTxAdvice") TransactionInterceptor transactionInterceptor) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, transactionInterceptor);
}
private static class CustomRuleBasedTransactionAttribute extends DefaultTransactionAttribute {
@Override
public boolean rollbackOn(Throwable ex) {
return !(ex instanceof NoRollbackException) && super.rollbackOn(ex);
}
}
}
如上述代码自定义CustomRuleBasedTransactionAttribute类继承DefaultTransactionAttribute类,然后重写rollbackOn方法,其中异常是自定义的NoRollbackException的话就不需要回滚了,否则还是走以前的逻辑。然后在创建DefaultTransactionAttribute对象的地方创建CustomRuleBasedTransactionAttribute对象即可实现。
|