[seata]分布式事务propagation为REQUIRES_NEW时,TransactionHook不会被调用

2024-04-28 349 views
8

背景:同一条线程下,全局事务A调用了REQUIRES_NEW的全局事务B

问题:

  • B的TransactionHook会被正常调用
  • A的TransactionHook部分方法不会被调用中,包括:afterPrepare、beforeCommit、afterCommit、beforeRollback、afterRollback、afterCompletion

A、B全局事务的钩子都需要被正常回调

示例代码如下:

    public void test() {
        TransactionHookManager.registerHook(aHook); //注册钩子A
        a(); //调用分布式事务A
    }

    @GlobalTransactional
    public void a() {
        TransactionHookManager.registerHook(bHook); //注册钩子B
        b(); //同一个线程调用分布式事务B
    }

    @GlobalTransactional(propagation = Propagation.REQUIRES_NEW)  // propagation为REQUIRES_NEW
    public void b() {
        //do something
    }

问题分析:在B事务结束时,清理了所有的TransactionHook,具体代码如下(cleanUp这一行)。这个逻辑会把A事务的钩子也误清理了。

https://github.com/seata/seata/blob/e7fe7f821abf4c51c8e88f1e322624309cef656f/tm/src/main/java/io/seata/tm/api/TransactionalTemplate.java#L141-L146

回答

1

问题存在,我认为应该把 private static final ThreadLocal<List<TransactionHook>> LOCAL_HOOKS = new ThreadLocal<>(); 改为 private static final ThreadLocal<Map<String, TransactionHook>> LOCAL_HOOKS = new ThreadLocal<>(); 虽然是一个线程但是可以用xid区分开hook,每个xid都是一个新的全局事务

6

指派给我处理

2

深入考虑了下,在传播为REQUIRED、NOT_SUPPORTED等级别也是存在问题的。

关于Hook这块社区是否有考虑做成一个完整的特性?包括RM侧的监听器、全局配置监听器等这类比较实用的功能。

8

not support下是没有xid,就不会清除hook,改成上面按xid角度通知和清除应该没问题

5

继承已有xid的情况,需要注意不能提前被清理。只有GlobalTransactionRole为Launcher时,才可以清理。

5

not support是先unbind的,理论上在执行hook相关功能不存在xid

7

rm侧后续会有hook或者listener提供,但不会让其影响分支事务的结果且不保证hook只执行一次

7

@slievrly