apache / incubator-seata

:fire: Seata is an easy-to-use, high-performance, open source distributed transaction solution.
https://seata.apache.org/
Apache License 2.0
25.25k stars 8.77k forks source link

Tcc模式是否支持动态数据源,如果不支持能否给个解决思路 #6731

Closed Theodore1965 closed 1 month ago

Theodore1965 commented 2 months ago

Ⅰ. Issue Description

使用动态数据源,TCC模式下,一直Retry无法提交, 如何不切换数据源,代码是没问题的

Ⅱ. Describe what happened

If there is an exception, please attach the exception trace:


Just paste your stack trace here!
**Java没有异常日志,以下是seata-server的日志**

 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: GlobalBeginRequest{transactionName='postRefund(java.lang.String)', timeout=30000}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [ServerHandlerThread_1_37_500] [io.seata.server.coordinator.Coordinator] [doGlobalBegin] [10.100.3.12:8091:5864237157175271941]: Begin new global transaction applicationId: platform-ocasher,transactionServiceGroup: default-group, transactionName: postRefund(java.lang.String),timeout:30000,xid:10.100.3.12:8091:5864237157175271941
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[single]: GlobalBeginResponse{xid='10.100.3.12:8091:5864237157175271941', extraData='null', resultCode=Success, msg='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[merged]: BranchRegisterRequest{xid='10.100.3.12:8091:5864237157175271941', branchType=TCC, resourceId='siOutBalanceCancel', lockKey='null', applicationData='{"actionContext":{"SiOutBalanceCancelDTO":{"clinicNo":"4067658","invoiceNo":"000000000014","mdtrtId":"335078951"},"action-start-time":1722820713839,"useTCCFence":true,"sys::prepare":"siOutBalanceCancel","sys::rollback":"rollbackBalanceCancel","sys::commit":"commitBalanceCancel","host-name":"10.100.3.13","actionName":"siOutBalanceCancel"}}'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [ForkJoinPool.commonPool-worker-3] [io.seata.server.coordinator.AbstractCore] [lambda$branchRegister$0] [10.100.3.12:8091:5864237157175271941]: Register branch successfully, xid = 10.100.3.12:8091:5864237157175271941, branchId = 5864237157175271943, resourceId = siOutBalanceCancel ,lockKeys = null
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[merged]: BranchRegisterResponse{branchId=5864237157175271943, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[merged]: BranchRegisterRequest{xid='10.100.3.12:8091:5864237157175271941', branchType=AT, resourceId='jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test', lockKey='fin_ipr_siinmaininfo:4067658_2', applicationData='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [ForkJoinPool.commonPool-worker-3] [io.seata.server.coordinator.AbstractCore] [lambda$branchRegister$0] [10.100.3.12:8091:5864237157175271941]: Register branch successfully, xid = 10.100.3.12:8091:5864237157175271941, branchId = 5864237157175271946, resourceId = jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test ,lockKeys = fin_ipr_siinmaininfo:4067658_2
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[merged]: BranchRegisterResponse{branchId=5864237157175271946, resultCode=Success, msg='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[merged]: BranchRegisterRequest{xid='10.100.3.12:8091:5864237157175271941', branchType=AT, resourceId='jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test', lockKey='fin_ipr_siinmaininfo:4067658_1,4067658_2', applicationData='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [ForkJoinPool.commonPool-worker-3] [io.seata.server.coordinator.AbstractCore] [lambda$branchRegister$0] [10.100.3.12:8091:5864237157175271941]: Register branch successfully, xid = 10.100.3.12:8091:5864237157175271941, branchId = 5864237157175271948, resourceId = jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test ,lockKeys = fin_ipr_siinmaininfo:4067658_1,4067658_2
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[merged]: BranchRegisterResponse{branchId=5864237157175271948, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[merged]: BranchRegisterRequest{xid='10.100.3.12:8091:5864237157175271941', branchType=AT, resourceId='jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test', lockKey='fin_opr_register:4067658_2', applicationData='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [ForkJoinPool.commonPool-worker-3] [io.seata.server.coordinator.AbstractCore] [lambda$branchRegister$0] [10.100.3.12:8091:5864237157175271941]: Register branch successfully, xid = 10.100.3.12:8091:5864237157175271941, branchId = 5864237157175271950, resourceId = jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test ,lockKeys = fin_opr_register:4067658_2
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[merged]: BranchRegisterResponse{branchId=5864237157175271950, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[merged]: BranchRegisterRequest{xid='10.100.3.12:8091:5864237157175271941', branchType=AT, resourceId='jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test', lockKey='fin_opr_register:4067658_1', applicationData='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [ForkJoinPool.commonPool-worker-3] [io.seata.server.coordinator.AbstractCore] [lambda$branchRegister$0] [10.100.3.12:8091:5864237157175271941]: Register branch successfully, xid = 10.100.3.12:8091:5864237157175271941, branchId = 5864237157175271952, resourceId = jdbc:oracle:thin:@127.0.0.1:1521/orcl/quit_test ,lockKeys = fin_opr_register:4067658_1
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[merged]: BranchRegisterResponse{branchId=5864237157175271952, resultCode=Success, msg='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: GlobalCommitRequest{xid='10.100.3.12:8091:5864237157175271941', extraData='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: BranchCommitResponse{xid='10.100.3.12:8091:5864237157175271941', branchId=5864237157175271943, branchStatus=PhaseTwo_CommitFailed_Retryable, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: result msg[single]: GlobalCommitResponse{globalStatus=CommitRetrying, resultCode=Success, msg='null'}, clientIp: 10.100.3.14, vgroup: default-group
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: BranchCommitResponse{xid='10.100.3.12:8091:5864237157175271941', branchId=5864237157175271943, branchStatus=PhaseTwo_CommitFailed_Retryable, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
ERROR --- [RetryCommitting_1_1] [io.seata.server.coordinator.Core] [lambda$doGlobalCommit$1] [10.100.3.12:8091:5864237157175271941]: Committing global transaction[10.100.3.12:8091:5864237157175271941] failed, caused by branch transaction[5864237157175271943] commit failed, will retry later.
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: BranchCommitResponse{xid='10.100.3.12:8091:5864237157175271941', branchId=5864237157175271943, branchStatus=PhaseTwo_CommitFailed_Retryable, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
ERROR --- [RetryCommitting_1_1] [io.seata.server.coordinator.Core] [lambda$doGlobalCommit$1] [10.100.3.12:8091:5864237157175271941]: Committing global transaction[10.100.3.12:8091:5864237157175271941] failed, caused by branch transaction[5864237157175271943] commit failed, will retry later.
 INFO --- [batchLoggerPrint_1_1] [io.seata.core.rpc.processor.server.BatchLogHandler] [run] []: receive msg[single]: BranchCommitResponse{xid='10.100.3.12:8091:5864237157175271941', branchId=5864237157175271943, branchStatus=PhaseTwo_CommitFailed_Retryable, resultCode=Success, msg='null'}, clientIp: 10.100.3.13, vgroup: default-group
ERROR --- [RetryCommitting_1_1] [io.seata.server.coordinator.Core] [lambda$doGlobalCommit$1] [10.100.3.12:8091:5864237157175271941]: Committing global transaction[10.100.3.12:8091:5864237157175271941] failed, caused by branch transaction[5864237157175271943] commit failed, will retry later.

### Ⅲ. Describe what you expected to happen

### Ⅳ. How to reproduce it (as minimally and precisely as possible)

1. xxx
2. xxx
3. xxx

Minimal yet complete reproducer code (or URL to code):

### Ⅴ. Anything else we need to know?

### Ⅵ. Environment:

- JDK version(e.g. `java -version`): 1.8
- Seata client/server version:   1.7.1
- Database version: oracle 11g
- Others:  dynamic-datasource 3.5.2
funky-eyes commented 2 months ago

如果出现retry client侧应该有日志,请把你的示例代码和,client侧的日志提交上来 If there should be a log on the client side of the retry, please send your sample code and the log commit on the client side

funky-eyes commented 2 months ago

一个比较简单的方案,如果你是spring的应用 DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); 将上面的SpringFenceHandler 包装后,用你的动态数据源处理后,再执行SpringFenceHandler的逻辑,或者你直接继承SpringFenceHandler进行处理动态数据源的逻辑 如果你不是spring的应用,你也可以通过这个api,自行扩展一个FenceHandler,再应用启动时第一时间放入DefaultCommonFenceHandler

A straightforward approach, if you are using a Spring application:

DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); After wrapping the SpringFenceHandler with your dynamic data source handling, proceed to execute the logic of SpringFenceHandler. Alternatively, you can extend SpringFenceHandler directly to incorporate the dynamic data source logic.

For applications not using Spring, you can also extend this API by independently extending a FenceHandler and placing it into DefaultCommonFenceHandler at startup.

Theodore1965 commented 2 months ago

一个比较简单的方案,如果你是spring的应用, DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); 将上面的SpringFenceHandler包装后,用你的动态数据源处理后,再执行SpringFenceHandler的逻辑,或者你直接继承SpringFenceHandler进行处理动态数据源的逻辑 如果你不是spring的应用,你也可以通过这个api,自行扩展一个FenceHandler,再应用启动时第一时间进入DefaultCommonFenceHandler

如果您使用 Spring 应用程序,那么一个简单的方法:

DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); 用动态数据源处理包装后SpringFenceHandler,继续执行 SpringFenceHandler 的逻辑。或者,您可以SpringFenceHandler直接扩展以合并动态数据源逻辑。

对于不使用 Spring 的应用程序,您还可以通过独立扩展并在启动时FenceHandler将其放入来扩展此 API。DefaultCommonFenceHandler

我看到SpringFenceHandler是2.0版本的,我用的是1.7.1,用TCCFenceHandler可以么, 1.7.1版本能否提供个关键代码部分的demo,万分感谢! 项目是Springboot2.7的

Theodore1965 commented 2 months ago

1.7.1版本,我是每次都要TCCFenceHandler.setDataSource()和TCCFenceHandler.setTransactionTemplate()么

iAmClever commented 2 months ago

1.7.1版本,我是每次都要TCCFenceHandler.setDataSource()和TCCFenceHandler.setTransactionTemplate()么 老哥,可以给下复现代码么(prepare、commit、rollback代码)

funky-eyes commented 2 months ago

一个比较简单的方案,如果你是spring的应用, DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); 将上面的SpringFenceHandler包装后,用你的动态数据源处理后,再执行SpringFenceHandler的逻辑,或者你直接继承SpringFenceHandler进行处理动态数据源的逻辑 如果你不是spring的应用,你也可以通过这个api,自行扩展一个FenceHandler,再应用启动时第一时间进入DefaultCommonFenceHandler中 如果您使用 Spring 应用程序,那么一个简单的方法: DefaultCommonFenceHandler.get().setFenceHandler(new SpringFenceHandler()); 用动态数据源处理包装后SpringFenceHandler,继续执行 SpringFenceHandler 的逻辑。或者,您可以SpringFenceHandler直接扩展以合并动态数据源逻辑。 对于不使用 Spring 的应用程序,您还可以通过独立扩展并在启动时FenceHandler将其放入来扩展此 API。DefaultCommonFenceHandler

我看到SpringFenceHandler是2.0版本的,我用的是1.7.1,用TCCFenceHandler可以么, 1.7.1版本能否提供个关键代码部分的demo,万分感谢! 项目是Springboot2.7的

1.7.1版本,我是每次都要TCCFenceHandler.setDataSource()和TCCFenceHandler.setTransactionTemplate()么

首先你自己创建一个TCCFenceHandler的子类的bean,seata侧就不会再构建TCCFenceHandler的bean,所以注入的是你的TCCFenceHandler,因为TCCFenceHandler是通过spring的DataSourceUtils获取的connection,只要你在这个之前,通过actionname能判断出来这个接口需要哪个数据源,或者通过commitMethod方法上的注解切换这个线程下的动态数据源的主数据源为哪个datasource就可以了,所以不需要每次都进行set之类的。

Theodore1965 commented 2 months ago

OK,明白了,感谢