SpringBoot全局事务管理

一、背景

springboot实现事务只需要在方法上添加@Transactional注解,但是需要在所有的service都加上事务,那就挺麻烦的。所以就需要采用AOP的方式实现全局事务处理。

考虑到作为不同项目来说,需要对多个不同的模块配置不同的超时时间的需求,所以采用注解的形式进行配置。

二、实现

1、创建注解类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TxDefinitionRegistrar.class)
public @interface EnableTxManager {

    /**
     * 切点,默认是medbanks 下所有service
     */
    String[] pointcut() default {"* cn.xxx..service..*(..)"};
    /**
     * 超时时间
     */
    int txMethodTimeOut() default 10;
}

2、创建一个注册器

public class TxDefinitionRegistrar implements ImportBeanDefinitionRegistrar {


    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        Map<String, Object> attributes = metadata.getAnnotationAttributes(EnableTxManager.class.getName());
        assert attributes != null;
        String pointcut = getPointcut(attributes);
        int txMethodTimeOut = getTxMethodTimeOut(attributes);

        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(GlobalTransactionConfig.class);
        definition.addPropertyValue("pointcut", pointcut);
        definition.addPropertyValue("txMethodTimeOut", txMethodTimeOut);
        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
        String beanName = StringUtils.uncapitalize(GlobalTransactionConfig.class.getSimpleName());
        registry.registerBeanDefinition(beanName, beanDefinition);

    }

    private String getPointcut(Map<String, Object> attributes) {
        Set<String> pointcut = new HashSet<>();
        for (String pc : (String[]) attributes.get("pointcut")) {
            if (StringUtils.hasText(pc)) {
                pointcut.add("execution(" + pc + " )");
            }
        }
        return Joiner.on("||").join(pointcut);
    }

    private int getTxMethodTimeOut(Map<String, Object> attributes) {
        return (int) attributes.get("txMethodTimeOut");
    }
}

3、定义全局事务处理类

public class GlobalTransactionConfig implements InitializingBean {

    /**
     * 超时时间
     */
    private int txMethodTimeOut;
    /**
     * 切点表达式
     */
    private String pointcut;

    public GlobalTransactionConfig() {
    }


    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {
        /* 配置事务管理规则,声明具备管理事务方法名.这里使用public void addTransactionalMethod(String methodName, TransactionAttribute attr)*/
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        Map<String, TransactionAttribute> nameMap = new HashMap<String, TransactionAttribute>();
        /*只读事物、不做更新删除等*/
        /*事务管理规则*/
        RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
        /*设置当前事务是否为只读事务,true为只读*/
        readOnlyRule.setReadOnly(true);
        /* transactiondefinition 定义事务的隔离级别;
         *  PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中*/
        readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
        /*抛出异常后执行切点回滚*/
        requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        /*PROPAGATION_REQUIRED:事务隔离性为1,若当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 */
        requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        /*设置事务失效时间,超过10秒,可根据hytrix,则回滚事务*/
        requireRule.setTimeout(txMethodTimeOut);

        nameMap.put("add*", requireRule);
        nameMap.put("save*", requireRule);
        nameMap.put("insert*", requireRule);
        nameMap.put("update*", requireRule);
        nameMap.put("delete*", requireRule);
        nameMap.put("remove*", requireRule);
        /*进行批量操作时*/
        nameMap.put("batch*", requireRule);
        nameMap.put("get*", readOnlyRule);
        nameMap.put("query*", readOnlyRule);
        nameMap.put("find*", readOnlyRule);
        nameMap.put("select*", readOnlyRule);
        nameMap.put("count*", readOnlyRule);
        source.setNameMap(nameMap);
        return new TransactionInterceptor(platformTransactionManager, source);

    }

    /**
     * 设置切面=切点pointcut+通知TxAdvice
     *
     * @return Advisor
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(this.pointcut);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());

    }


    @Override
    public void afterPropertiesSet() throws Exception {
        Assert.state(this.txMethodTimeOut >= -1, "txMethodTimeOut must be set");
        Assert.hasText(this.pointcut, "pointCut must be set");
    }

    public int getTxMethodTimeOut() {
        return txMethodTimeOut;
    }

    public void setTxMethodTimeOut(int txMethodTimeOut) {
        this.txMethodTimeOut = txMethodTimeOut;
    }

    public String getPointcut() {
        return pointcut;
    }

    public void setPointcut(String pointcut) {
        this.pointcut = pointcut;
    }
}

三、使用

@SpringBootApplication
@EnableTxManager(txMethodTimeOut = 10)
public class TradeOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(TradeOrderApplication.class, args);
    }

}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot中配置全局事务需要使用Spring事务管理器和注解@Transactional。下面是一个简单的全局事务配置示例: 1. 配置数据源 在application.properties文件中配置数据源相关信息: ``` spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=root ``` 2. 配置事务管理器 创建一个配置类,配置事务管理器: ```java @Configuration @EnableTransactionManagement public class TransactionConfig { @Bean(name = "transactionManager") public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` 3. 开启全局事务 在需要开启事务的方法上添加@Transactional注解即可: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional public void addUser(User user) { userDao.addUser(user); } } ``` 其中@Transactional注解的属性可以根据需要进行配置,例如: - propagation:事务的传播行为,默认值为REQUIRED。 - isolation:事务的隔离级别,默认值为DEFAULT。 - readOnly:指定事务是否为只读,默认值为false。 - timeout:指定事务的超时时间,默认值为-1(表示使用数据库默认超时时间)。 这样配置之后,当执行addUser方法时,如果出现异常或者抛出RuntimeException,则整个方法会进行回滚,保证数据一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值