本文介绍: 编程事务指的是通过编码方式实现事务声明事务基于 AOP,将具体的逻辑事务处理解耦(编程事务在这边不做过多陈述)。,一种是在(XML)中做相关事务规则声明,另一种是基于方式。先看一张思维导图(来自互联网)

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切换不生效;

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拦截,为了解决这个问题可以使用

(Tservice)AopContext.currentProxy().test1();

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

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

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

mybatisplus解决方案

mybatisplus官方提供了@DSTransactional注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DSTransactional {
}

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

    @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);
    }

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

应该怎么做

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

    @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

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

原文地址:https://blog.csdn.net/heroguo007/article/details/134740352

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_28870.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注