dynamic-datasource多数据源事务

Spring 事务管理分为编程式和声明式两种 编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体的逻辑与事务处理解耦(编程式事务在这边不做过多陈述)。

声明式事务有两种方式 ,一种是在配置文件 (XML)中做相关的事务规则声明,另一种是基于 @Transactional 注解的方式。

先看一张思维导图(来自互联网)

@Transactional注解

@Transactional实质是使用了JDBC的事务来进行事务控制的

@Transactional基于Spring的动态代理的机制

@Transactional实现原理

1:事务开始时,通过AOP机制,生成一个代理connection对象,并将其放入DataSource实例的某个与DataSourceTransactionManager相关的某处容器中。

在接下来的整个事务中,客户代码都应该使用该connection连接数据库,执行所有数据库命令[不使用该connection连接数据库执行的数据库命令,在本事务回滚的时候得不到回滚](物理连接connection逻辑上新建一个会话session;DataSource与TransactionManager配置相同的数据源)

2:事务结束时,回滚在第1步骤中得到的代理connection对象上执行的数据库命令,然后关闭该代理connection对象(事务结束后,回滚操作不会对已执行完毕的SQL操作命令起作用)

事务失效

通过@Transactional实现原理可以发现;

  1. Spring@Transactional不支持跨数据源事物,Spring 事物控制是基于数据库链接进行的,当数据源切换后,数据库链接切换,事物回滚只能回退,当前持有的链接。
  2. Spring开启事物后,会将当前数据库及数据库链接资源进行线程绑定,导致数据源切换失效(数据源切换执行后,并未获取到新的数据库链接)

怎么解决多数据源问题

新平台目前使用的是@DS注解来切换数据源,通过DynamicDataSourceAnnotationInterceptor我们可以看到,实现的是MethodInterceptor,在通过注解进行数据源切换,由于@Transactional对数据库连接绑定,导致@DS切换不生效;

java 复制代码
public Object invoke(MethodInvocation invocation) throws Throwable {
        String dsKey = this.determineDatasourceKey(invocation);
        DynamicDataSourceContextHolder.push(dsKey);

        Object var3;
        try {
            var3 = invocation.proceed();
        } finally {
            DynamicDataSourceContextHolder.poll();
        }

        return var3;
    }

    private String determineDatasourceKey(MethodInvocation invocation) {
        String key = this.dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis());
        return key.startsWith("#") ? this.dsProcessor.determineDatasource(invocation, key) : key;
    }

解决方案

由于事务的开启是通过AOP实现的,而service 方法内调用绕过了AOP拦截,为了解决这个问题可以使用

java 复制代码
(Tservice)AopContext.currentProxy().test1();

通过@Transactional原理可知@Transactional是单事务,因此在具体的方法上

```java
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void test1(){

但是这样就没法控制多数据源事务;

mybatis-plus解决方案

mybatis-plus官方提供了@DSTransactional注解

java 复制代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DSTransactional {
}

在没有seata的情况下,通过DynamicDataSourceAnnotationAdvisor 管理事务,DynamicDataSourceAnnotationAdvisor的拦截器是DynamicLocalTransactionInterceptor

java 复制代码
    @Role(2)
    @Bean
    @ConditionalOnProperty(
        prefix = "spring.datasource.dynamic",
        name = {"seata"},
        havingValue = "false",
        matchIfMissing = true
    )
    public Advisor dynamicTransactionAdvisor() {
        DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor();
        return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
    }

具体的大家可以自行了解一下;

应该怎么做

通过上面的说明,想必大家已经知道,我们应该怎样做

java 复制代码
    @DSTransactional
    public int addEn(Users users) {

        (Tservice)AopContext.currentProxy().insertUser(users);
        (Tservice)AopContext.currentProxy().insertUser1(users);

        if ("aa".equals(users.getName())) {
            throw new RuntimeException();
        }
        return 1;

    }


    public void insertUser(Users users) {
        usersMapper.insertUser(users);
    }


    public void insertUser1(Users users) {
        usersMapper.insertUser1(users);
    }

usermapper

java 复制代码
    @DS("master")
    Long insertUser(Users users);

    @DS("slave")
    Long insertUser1(Users users);

后续改进

Spring Boot整合了Atomikos和Bitronix两个JTA(Java Transaction API)的实现,但在2.3.0的版本中Bitronix不推荐使用Bitronix了。Atomikos提供了两款分布式事务产品级解决方案,分别是ExtremeTransactions和TransactionsEssentials,前者需要商业授权,后者是开源免费使用版本,TransactionsEssentials是免费的,可无缝升级为ExtremeTransactions版本;后续我们可以整合Atomikos,目前若依也给出了整合方案;

相关推荐
gma9991 小时前
Etcd 框架
数据库·etcd
爱吃青椒不爱吃西红柿‍️1 小时前
华为ASP与CSP是什么?
服务器·前端·数据库
Yz98762 小时前
hive的存储格式
大数据·数据库·数据仓库·hive·hadoop·数据库开发
苏-言2 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
Ljw...2 小时前
索引(MySQL)
数据库·mysql·索引
菠萝咕噜肉i2 小时前
超详细:Redis分布式锁
数据库·redis·分布式·缓存·分布式锁
长风清留扬2 小时前
一篇文章了解何为 “大数据治理“ 理论与实践
大数据·数据库·面试·数据治理
OpsEye2 小时前
MySQL 8.0.40版本自动升级异常的预警提示
数据库·mysql·数据库升级
Ljw...2 小时前
表的增删改查(MySQL)
数据库·后端·mysql·表的增删查改
远歌已逝5 小时前
维护在线重做日志(二)
数据库·oracle