V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
7911364440
V2EX  ›  Java

关于动态切换数据源的问题

  •  
  •   7911364440 · 2022-09-22 13:53:19 +08:00 · 2172 次点击
    这是一个创建于 554 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前使用的是 AbstractRoutingDataSource+AOP 动态切换数据源,现在有个需求要在一个请求中分别对 A 库和 B 库各新增一条数据。

    伪代码如下:

    
    public class FooController {
    
    	
        @PostMapping(value = "/foo")
        public void foo() {
        	// AOP 会拦截这两个 service 中的方法,然后切换数据源
        	fooService.save();	// 在 A 库插入数据,这里是正常的
            barService.save();  // 在 B 库插入数据,这里切换不了数据源,使用的还是 A 数据源
        }
        
    }
    
    

    问题是只有第一个方法切换数据源有效,第二个方法切换不了数据源。
    应该是第二个方法切换数据源之后,没有触发下面这段方法,想问下有没有其它解决方案?

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

    PS:orm 框架用的 jpa

    第 1 条附言  ·  2022-09-22 17:13:30 +08:00
    AOP:
    ```java

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    Class<?> clazz = signature.getDeclaringType();
    Method method = signature.getMethod();

    if (method.isAnnotationPresent(DB.class)) {
    DynamicDataSourceHolder.setKey(method.getAnnotation(DB.class).value().getKey());
    } else if (clazz.isAnnotationPresent(DB.class)) {
    DynamicDataSourceHolder.setKey(clazz.getAnnotation(DB.class).value().getKey());
    } else {
    DynamicDataSourceHolder.setKey(DataSourceKey.DEFAULT.getKey());
    }

    try {
    return pjp.proceed();
    } finally {
    DynamicDataSourceHolder.remove();
    }
    }


    ```
    15 条回复    2022-10-08 11:23:18 +08:00
    nekolr
        1
    nekolr  
       2022-09-22 14:37:43 +08:00
    建议贴一下 aop 的相关代码
    wolfie
        2
    wolfie  
       2022-09-22 14:47:27 +08:00
    注掉 fooService 看看,能不能走 AOP 。
    Kaiv2
        3
    Kaiv2  
       2022-09-22 14:50:32 +08:00
    需求是什么?
    joooooker21
        4
    joooooker21  
       2022-09-22 14:53:10 +08:00
    DynamicDataSourceHolder.setKey( b )
    sirierx
        5
    sirierx  
       2022-09-22 14:54:33 +08:00
    baomidou.dynamic.datasource
    7911364440
        6
    7911364440  
    OP
       2022-09-22 15:13:07 +08:00
    @wolfie 两个 service 都是可以被 aop 拦截的
    wolfie
        7
    wolfie  
       2022-09-22 16:20:57 +08:00
    贴部分代码吧。
    在看看有没有涉及到 异步 相关的东西。
    cheng6563
        8
    cheng6563  
       2022-09-22 16:25:07 +08:00
    第二个方法必须要启动新事物,不然事务管理器会保持连接
    so2back
        9
    so2back  
       2022-09-22 16:36:50 +08:00
    需要切换数据源的方法用 @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)注解试试,也就是按楼上说的,需要起一个新的事务
    7911364440
        10
    7911364440  
    OP
       2022-09-22 17:14:47 +08:00
    @cheng6563
    @so2back
    在两个 service 都加上了 @Transactional(propagation = Propagation.REQUIRES_NEW) 也不行
    MrZYB
        11
    MrZYB  
       2022-09-22 17:26:06 +08:00
    切换数据源写个 setDataSource 方法,在调用第 2 个 service.save()时手动切换数据源。
    git00ll
        12
    git00ll  
       2022-09-22 17:33:00 +08:00
    AbstractPlatformTransactionManager 类上有一个 setTransactionSynchronization 方法,可以控制不是真实事物情况下,是否需要使用事务管理器进行连接同步。

    可选值为
    SYNCHRONIZATION_ALWAYS ,SYNCHRONIZATION_ON_ACTUAL_TRANSACTION ,SYNCHRONIZATION_NEVER 三个字段。

    你这里的情况,把事务管理器上的 setTransactionSynchronization 设为 SYNCHRONIZATION_ON_ACTUAL_TRANSACTION ,试试看
    czn6mx
        13
    czn6mx  
       2022-09-22 19:18:50 +08:00
    AOP after 清掉 ThreadLocal dataSourceKey
    cslive
        14
    cslive  
       2022-09-23 08:56:21 +08:00
    jpa 不需要 aop 切换,需要单独设置每个数据源针对的实体类所在的位置
    Aresxue
        15
    Aresxue  
       2022-10-08 11:23:18 +08:00   ❤️ 1
    生产级代码就别自己写了,用 https://github.com/baomidou/dynamic-datasource-spring-boot-starter 这个好了,唯一要注意的是分布式事务的部分需要自己重写一下,如果是为了学习也可以看一下人家的代码,也是 AbstractRoutingDataSource 这个路子
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3255 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 10:50 · PVG 18:50 · LAX 03:50 · JFK 06:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.