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,目前若依也给出了整合方案;

相关推荐
云和数据.ChenGuang1 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys1 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi1 小时前
SQL注入的那些面试题总结
数据库·sql
建投数据2 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
xlsw_3 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
Hacker_LaoYi3 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀3 小时前
Redis梳理
数据库·redis·缓存
独行soc3 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
你的微笑,乱了夏天4 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺4 小时前
分布式系统架构:服务容错
数据库·架构