返回顶部
首页 > 资讯 > 后端开发 > Python >@Transactional跟@DS动态数据源注解冲突的解决
  • 741
分享到

@Transactional跟@DS动态数据源注解冲突的解决

2024-04-02 19:04:59 741人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录@Transactional跟@DS动态数据源注解冲突背景@Transactional执行流程解决方法动态数据源切换失败由事务@Transactional注解导致动态数据源切换失

@Transactional跟@DS动态数据源注解冲突

背景

前阵子写一个项目时,有个需求是要往3个库,3个表里插入数据,在同一个方法里,公司是用baomidou的@DS注解来实现配置动态数据源的。这是背景,然后呢,我在一个service方法里,就操作了这三张表,同时,我还加上了@Transactional注解,因为该方法是个save方法,我就加上了事务。

伪代码如下:


spring:
  datasource:
    dynamic:
      primary: A 
      datasource:
        A:
          url:..
          driver-class-name: com.Mysql.jdbc.Driver
          username: root
          passWord:
        B:
          url: ..
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password:
        C:
          url: ..
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password:

@Mapper
@DS("A")
public interface AMapper{
      @Insert("insert into a ...")
      void save();
}

@Mapper
@DS("B")
public interface BMapper{
      @Insert("insert into b ...")
      void save();
}

@Mapper
@DS("C")
public interface CMapper{
      @Insert("insert into c ...")
      void save();
}

public class aService{ 
@Autowired
private aMapper、bMapper、cMapper
 
    @Transactional
    public void save(){
    aMapper.save();
    bMapper.save(); #报错
    cMapper.save();
    }    
}

开发完成用postman自测时,发现bMapper.save()那一行报错了,报错内容:找不到b表。如果把@Transactional注释掉,代码正常运行,数据成功落库。我们明明在3个mapper上面都加了@DS注解来切换数据源,那为啥加了@Transactional就不行了呢?

@Transactional执行流程

  • save方法添加了 @Transactional 注解,Spring 事务就会生效。此时,Spring TransactionInterceptor 会通过 aop 拦截该方法,创建事务。而创建事务,势必就会获得数据源。那么,TransactionInterceptor 会使用 Spring DataSourceTransactionManager 创建事务,并将事务信息通过 ThreadLocal 绑定在当前线程
  • 而事务信息,就包括事务对应的 Connection 连接。那也就意味着,还没走到 OrderMapper 的查询操作,Connection 就已经被创建出来了。并且,因为事务信息会和当前线程绑定在一起,在 OrderMapper 在查询操作需要获得 Connection 时,就直接拿到当前线程绑定的 Connection ,而不是 OrderMapper 添加 @DS 注解所对应的 DataSource 所对应的 Connection 。
  • OK ,那么我们现在可以把问题聚焦到 DataSourceTransactionManager 是怎么获取 DataSource 从而获得 Connection 的了。对于每个 DataSourceTransactionManager 数据库事务管理器,创建时都会传入其需要管理的 DataSource 数据源。在使用 dynamic-datasource-spring-boot-starter 时,它创建了一个 DynamicRoutingDataSource ,传入到 DataSourceTransactionManager 中。
  • 而 DynamicRoutingDataSource 负责管理我们配置的多个数据源。例如说,本示例中就管理了 a、b、c 三个数据源,并且默认使用 a 数据源。那么在当前场景下,DynamicRoutingDataSource 需要基于 @DS 获得数据源名,从而获得对应的 DataSource ,结果因为我们在 Service 方法上,并没有添加 @DS 注解,所以它只好返回默认数据源,也就是 a 。故此,就发生了 找不到表 的异常。

我们在上面了解到,因为@Transactional会创建事务然后获得数据源,因为我们service方法上没有@DS注解,就拿了默认数据源,并且在这之后,这个事务信息会通过threadLocal跟当前线程绑定,事务信息包括了connection连接,也就意味着,在进入这个service方法的时候,当前事务就绑定了数据源a,在运行到bMapper.save()时,因为connection已经存在,所以拿到的数据源还是a,这时候就找不到b库里的表了。

解决方法

把这三个入库操作分为3个独立的方法,并且都加上@Transactional和 @DS注解(在service上加)。ps:在完成了aMapper.save()之后去调用bMapper.save()时,一定要把@Transactional设置为Propagation.REQUIRES_NEW,这样在调用另一个事务方法时,TransactionInterceptor 会将原事务挂起,暂时性的将原事务信息和当前线程解绑。

pps:

在一个事务方法里用this来调用另一个事务方法时,@DS也会起作用,原因是this调用的不是事务对象,不会开启事务。想具体了解可以看我之前发的这篇文章 //www.jb51.net/article/222082.htm

动态数据源切换失败

由事务@Transactional注解导致动态数据源切换失效的问题

不多BB,直接上代码:


public class DataSourceKey {
    
    public final static String USER = "userDataSource";
    
    public final static String REPORT = "reportDataSource";
    
    final static List<String> SOURCES = ImmutableList.of(USER, REPORT);
    
    public static String getDataSourceKey(String pack) {
        return SOURCES.stream().filter(s -> s.startsWith(pack)).findFirst().orElse(USER);
    }
}

@Component
@Aspect
@Order(-1)
@Slf4j
public class DynamicDataSourceAspect {
    @Pointcut("execution(* com.in.g.data.mapper..*.*(..))")
    public void dataSourcePointcut() {
    }
    @Before("dataSourcePointcut()")
    public void doBefore(JoinPoint point) throws Throwable {
        log.debug("切换数据源开始。。。。。。。。。。。。");
        Package pack = point.getSignature().getDeclaringType().getPackage();
        String str = StringUtils.substringAfterLast(pack.getName(), ".");
        String dataSourceKey = DataSourceKey.getDataSourceKey(str);
        DynamicDataSourceHolder.set(dataSourceKey);
        log.debug("切换数据源成功,当前数据源:{}", dataSourceKey);
    }
    @After("dataSourcePointcut()")
    public void doAfterReturning() throws Throwable {
        DynamicDataSourceHolder.clear();
    }
}


public class DynamicDataSourceHolder {
    public static ThreadLocal<String> keyHolder = new ThreadLocal<>();
    public static void clear() {
        keyHolder.remove();
    }
    public static void set(String key) {
        keyHolder.set(key);
    }
    public static String get() {
        return keyHolder.get();
    }
}


public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceHolder.get();
    }
}

//正确的代码   --这里偷懒了,直接controller调用dao层
@GetMapping("/testdb")
    public String testDateSources(){
     //缩小事务的范围
       add();
       rptFieldMapper.selectxxxx();
       
       return "sss";
    }
    @Transactional(rollbackFor = Exception.class)
    public void add() {
     userMapper.insertXXXX(xxxx);
 }

    //错误的代码,@Transactional注解会导致 数据源切换失败
    @GetMapping("/testdb")
    @Transactional(rollbackFor = Exception.class)
    public String testDateSources(){  
        userMapper.insertXXXX(xxxx);
        rptFieldMapper.selectXXXX();
        
        return "sss";
    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: @Transactional跟@DS动态数据源注解冲突的解决

本文链接: https://lsjlt.com/news/134866.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • @Transactional跟@DS动态数据源注解冲突的解决
    目录@Transactional跟@DS动态数据源注解冲突背景@Transactional执行流程解决方法动态数据源切换失败由事务@Transactional注解导致动态数据源切换失...
    99+
    2024-04-02
  • 使用@DS轻松解决动态数据源的问题
    目录@DS解决动态数据源问题引入maven修改Application.yml@DS注解说明@DS解决动态数据源问题 动态切换数据源,无非是继承org.springframework....
    99+
    2024-04-02
  • 解决动态库的符号冲突
    一次debug遇到的疑惑某天发现一个程序有点问题,祭上print大法。 一次debug遇到的疑惑 某天发现一个程序有点问题。祭上print大法,在关键的 lib_func() 函数里添加 print 调试信息...
    99+
    2020-12-02
    解决动态库的符号冲突
  • SpringBoot @DS注解实现多数据源配置及问题解决
    一、导入依赖: com.baomidou dynamic-datasource-spring-boot-starter 3.5.0 二...
    99+
    2023-09-01
    java Powered by 金山文档
  • springboot-启动bean冲突的解决
    目录启动bean冲突启动提示bean重复问题先说结论原理启动bean冲突 在一次启动中遇到了bean冲突的问题,提示存在两个名称重复的bean org.springframework...
    99+
    2024-04-02
  • @Transactional注解异常报错之多数据源详解
    目录@Transactional注解报错之多数据源1.在配置数据源的同时2.一定要在需要使用事物注解的数据源配置里@Transactional 错误使用的几种场景@Transacti...
    99+
    2024-04-02
  • Android滑动冲突的完美解决
    Android滑动在智能手机上是必备的操作,但是在开发的时候,你是否和我一样,经常会遇到滑动冲突的问题,比如最简单需要在ListView里面添加一个侧滑动作,这时候冲突时必然的...
    99+
    2022-06-06
    Android
  • ViewPager2滑动冲突的解决方法
    ViewPager2滑动冲突解决,供大家参考,具体内容如下 本文章对ViewPager2的滑动冲突没有提供完善的解决方案,仅为巩固解决滑动冲突方面的知识 首先看看没有解决滑动冲突时...
    99+
    2024-04-02
  • 解决Pg新增数据主键冲突
    更新索引至最大值:select setval(""demo".test_id_seq", (SELECT MAX("id") FROM demo.test)); 查询下一个序列值:select nextval(""dem...
    99+
    2021-10-12
    解决Pg新增数据主键冲突
  • springboot怎么集成@DS注解实现数据源切换
    这篇文章主要介绍“springboot怎么集成@DS注解实现数据源切换”,在日常操作中,相信很多人在springboot怎么集成@DS注解实现数据源切换问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”sprin...
    99+
    2023-06-29
  • Android listview的滑动冲突解决方法
    Android listview的滑动冲突解决方法 在Android开发的过程中,有时候会遇到子控件和父控件都要滑动的情况,尤其是当子控件为listview的时候。就比如在一个...
    99+
    2022-06-06
    方法 listview Android
  • win10的1903驱动冲突怎么解决
    本篇内容介绍了“win10的1903驱动冲突怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!第一种方法 找到桌面上的【此电脑】图标,右...
    99+
    2023-07-01
  • Spring和SpringMVC扫描注解类冲突的解决方案
    目录Spring和SpringMVC扫描注解类冲突最正确的配置方式也可以用直接扫描的方式几种不同配置的测试Spring和SpringMVC注解扫描注意事项现象方法Spring和Spr...
    99+
    2024-04-02
  • Android滑动冲突问题的解决方法
    叙述 滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。 ...
    99+
    2022-06-06
    方法 Android
  • android多种滑动冲突的解决方案
    一、前言 Android 中解决滑动的方案有2种:外部拦截法 和内部拦截法。 滑动冲突也存在2种场景: 横竖滑动冲突、同向滑动冲突。 所以我就写了4个例子来学习如何...
    99+
    2022-06-06
    解决方案 Android
  • Android滑动冲突的完美解决方案
    关于滑动冲突 在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂的页面,特别是为了兼容小屏手机而使用了ScrollView以后,就会出现很多点击事件...
    99+
    2022-06-06
    解决方案 Android
  • Android滑动事件冲突的解决方法
    滑动是Android中不可缺少的一部分,多个滑动必然会产生冲突,比如我们最常见的是ScrollView中嵌套了ListView,一般做法是计算出ListView的总高度,这样就...
    99+
    2022-06-06
    方法 事件 Android
  • springboot集成@DS注解实现数据源切换的方法示例
    目录启用@DS实现数据源切换POM内添加核心jar包yml配置“核心”-使用@DS注解最后启用@DS实现数据源切换 POM内添加核心jar包         ...
    99+
    2024-04-02
  • 关于@DS注解切换数据源失败的原因实战记录
    目录项目场景:问题排查过程第一个问题,数据源没有载入第二个问题,@DS注解切换数据源无效总结项目场景: 一位好友在陈年老代码中想要加入mybatis-plus和boumidou的多数...
    99+
    2023-05-19
    ds切换数据源不起作用 @ds注解切换数据源失败
  • 浅谈Android View滑动冲突的解决方法
    引言 这一篇文章我们就通过介绍滑动冲突的规则和一个实例来更加深入的学习View的事件分发机制。 1、外部滑动方向和内部滑动方向不一致 考虑这样一种场景,开发中我们经常使用Vie...
    99+
    2022-06-06
    view 方法 Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作