QNJR-GROUP / EasyTransaction

A distribute transaction solution(分布式事务) unified the usage of TCC , SAGA ,FMT (seata/fescar AutoCompensation), reliable message, compensate and so on;
Apache License 2.0
2.36k stars 809 forks source link

refactor: 修改事务传播级别为 REQUIRED,允许与主事务使用同一个事务 #151

Closed HasonHuang closed 4 years ago

HasonHuang commented 4 years ago

问题

  1. 主事务在提交之前 crash,未完成事务和事务内容已经被存储到数据库中,导致服务启动后再次执行不必要的操作(虽然执行了一些操作,结果是正确的)。

原因

  1. 创建 DataBaseTransactionLogWritterImpl 时使用 PROPAGATION_REQUIRES_NEW 传播级别,创建事务日志时无法与主事务使用同一个事务。
  2. DatabaseExtensionsSuiteConfigurationDataBaseTransactionLogConfiguration 创建 DataBaseTransactionLogWritterImpl 时都是使用 EasyTrans 创建的数据源,导致创建日志时无法与主事务使用同一个事务。

为什么可以优化

  1. DataBaseTransactionLogWritterImpl 创建日志记录时,在 beforeCommit 与主事务之间是同步操作(同一个线程),如果使用用户程序的数据源,可以与主事务的使用同一个事务管理。
  2. DataBaseTransactionLogWritterImpl#appendTransLog 没有在 afterCompletionafterCommit 中执行。
  3. DataBaseTransactionLogWritterImpl#appendTransLog 除了第 1 点的情况,其他执行场景与用户事务(主事务)无关,不会因为用户事务回滚导致无法正常完成事务。
  4. DataBaseTransactionLogWritterImpl#cleanFinishedLogs 由一个异步线程执行。
skyesx commented 4 years ago

这里是不能够修改成required的,事务日志会记录 可能/已经 与远程发生交互的接口。

如果回滚掉了这些信息的话,就在crash recovery的时候,没有办法获得哪些已经执行过,也就没办法调用crash场景下的cancel

HasonHuang commented 4 years ago

感谢回复,我看见事务参与者是在钩子的 afterCompletion 阶段异步触发,如果在这阶段之前 crash 或回滚,是否表示参与者一定没有被触发?

skyesx commented 4 years ago

以TCC为例,afterCompletion这部分触发的是Cancel或者Confirm操作,TRY操作会在事务过程中就被触发了

回滚时,为了消除TRY可能已经执行的影响,所以必须记录下哪些TRY可能被调用过了,然后调用其对应Cancel方法