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

打算用 Spring AbstractRoutingDataSource 做一主多从 但是和事务搭配实现上感觉不太对头,怎么解决?

  •  
  •   Aruforce · 2021-04-06 18:40:13 +08:00 · 1027 次点击
    这是一个创建于 1087 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求

    1. AbstractRoutingDataSource 想根据当前的事务状态来 routing 
    2. 在从库上禁用更新操作
    3. 每个请求 打在一个数据源上
    

    问题

    1. 在进行 data source routing 时,TransactionSynchronizationManager.isActualTransactionActive 总是返回 false ;按照代码的语义实际上是在事务之中的; 请问有什么其他的 API 可以使用么?
    2. 在 data source routing 中想向 TransactionSynchronizationManager 注册 TransactionSynchronization 用于资源清理,但是返回 synchronization is not active
    

    stackoverflow 似乎有人遇到了相同的问题

    https://stackoverflow.com/questions/9203122/routing-read-write-transactions-to-primary-and-read-only-transactions-to-replica

    Christophe Fondacci 这个回答。。似乎没有解决

    第 1 条附言  ·  2021-04-07 08:38:03 +08:00

    搞定了。。。不要重写事务管理器。。。

    1. 重写 DataSourceTransactionManager的dobegin 方法 使用 如下代码来判断是否进入 事务;

    JdbcTransactionObjectSupport transaction1 = (JdbcTransactionObjectSupport) transaction;
            if (!transaction1.hasConnectionHolder() || transaction1.getConnectionHolder().isSynchronizedWithTransaction()){
                logger.info("it seems it is in transaction ");
    //do thread local bind  in transaction status
            }
    

    2. 重写 DataSourceTransactionManager的prepareSynchronization 方法

       @Override
        protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
            super.prepareSynchronization(status, definition);
            if (MasterSlavesDataSourceSynchronization.isInTransaction()){
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCompletion(int status) {
                      // do your thread local resource clean
                    }
                });
            }
        }
    

    3. 对 Connection 及 statement 以及 prepareStatement 的 更新及事务方法 进行 拦截 在 slave data source 上 直接 抛异常即可

    4. 要求更新 操作必须使用事务, 事务的所有操作都会route 到master,其余再无其他要求

    第 2 条附言  ·  2021-04-07 08:38:38 +08:00
    不过要 重写事务管理器
    2 条回复    2021-04-06 20:49:10 +08:00
    coderwl
        1
    coderwl  
       2021-04-06 19:04:35 +08:00
    直接用现成的吧,我司用的 sharding-jdbc , 写 /读操作自动路由到主 /从库,支持单库事务,可以看下
    Aruforce
        2
    Aruforce  
    OP
       2021-04-06 20:49:10 +08:00 via Android
    @coderwl 我不是要用 我是要做个改造…
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5354 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 08:22 · PVG 16:22 · LAX 01:22 · JFK 04:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.