funky-eyes commented on code in PR #6706:
URL: https://github.com/apache/incubator-seata/pull/6706#discussion_r1694448684


##########
core/src/main/java/org/apache/seata/core/context/RootContext.java:
##########
@@ -60,6 +61,26 @@ private RootContext() {
      */
     public static final String KEY_TIMEOUT = "TX_TIMEOUT";
 
+    /**
+     * The constant KEY_RESOURCE_ID.
+     */
+    public static final String KEY_RESOURCE_ID = "TX_RESOURCE_ID";

Review Comment:
   Rootcontext不应该用来存放这些数据
   Rootcontext should not be used to store this data



##########
spring/src/main/java/org/apache/seata/rm/fence/SpringFenceHandler.java:
##########
@@ -41,12 +31,32 @@
 import org.apache.seata.integration.tx.api.fence.store.CommonFenceStore;
 import 
org.apache.seata.integration.tx.api.fence.store.db.CommonFenceStoreDataBaseDAO;
 import org.apache.seata.integration.tx.api.remoting.TwoPhaseResult;
+import org.apache.seata.rm.fence.interceptor.TccFenceCommitInterceptor;
+import org.apache.seata.rm.fence.interceptor.TccFencePrepareInterceptor;
+import org.apache.seata.rm.fence.interceptor.TccFenceRollbackInterceptor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.aop.Advisor;
+import org.springframework.aop.framework.Advised;
 import org.springframework.jdbc.datasource.DataSourceUtils;
 import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.interceptor.TransactionAttributeSource;
+import org.springframework.transaction.interceptor.TransactionInterceptor;
+import 
org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.transaction.support.TransactionTemplate;
 
+import javax.sql.DataSource;

Review Comment:
   同上
   ditto



##########
spring/src/main/java/org/apache/seata/rm/fence/SpringFenceHandler.java:
##########
@@ -187,40 +235,111 @@ public boolean commitFence(Method commitMethod, Object 
targetTCCBean,
      */
     @Override
     public boolean rollbackFence(Method rollbackMethod, Object targetTCCBean,
-                                        String xid, Long branchId, Object[] 
args, String actionName) {
-        return transactionTemplate.execute(status -> {
+                                 String xid, Long branchId, Object[] args, 
String actionName) {
+        if (hasTransactionAspectBeforeInterceptor(rollbackMethod, 
targetTCCBean, TccFenceRollbackInterceptor.class)) {
             try {
-                Connection conn = DataSourceUtils.getConnection(dataSource);
-                CommonFenceDO commonFenceDO = 
COMMON_FENCE_DAO.queryCommonFenceDO(conn, xid, branchId);
-                // non_rollback
-                if (commonFenceDO == null) {
-                    boolean result = insertCommonFenceLog(conn, xid, branchId, 
actionName, CommonFenceConstant.STATUS_SUSPENDED);
-                    LOGGER.info("Insert common fence record result: {}. xid: 
{}, branchId: {}", result, xid, branchId);
-                    if (!result) {
-                        throw new CommonFenceException(String.format("Insert 
common fence record error, rollback fence method failed. xid= %s, branchId= 
%s", xid, branchId),
-                                FrameworkErrorCode.InsertRecordError);
-                    }
-                    return true;
-                } else {
-                    if (CommonFenceConstant.STATUS_ROLLBACKED == 
commonFenceDO.getStatus() || CommonFenceConstant.STATUS_SUSPENDED == 
commonFenceDO.getStatus()) {
-                        LOGGER.info("Branch transaction had already rollbacked 
before, idempotency rejected. xid: {}, branchId: {}, status: {}", xid, 
branchId, commonFenceDO.getStatus());
+                // The tcc transaction is activated on the service side.
+                RootContext.bindTccLocalTxActive(TccLocalTxActive.ACTIVE);
+                RootContext.bindTccRollbackResult(false);
+                rollbackMethod.invoke(targetTCCBean, args);
+                Boolean result = RootContext.getTccRollbackResult();
+                return result;
+            } catch (Exception e) {
+                throw new 
SkipCallbackWrapperException(ExceptionUtil.unwrap(e));
+            } finally {
+                RootContext.unbindTccLocalTxActive();
+                RootContext.unbindTccRollbackResult();
+            }
+        } else {
+            return transactionTemplate.execute(status -> {
+                try {
+                    // The tcc transaction is not activated on the service 
side.
+                    
RootContext.bindTccLocalTxActive(TccLocalTxActive.UN_ACTIVE);
+                    Connection conn = 
DataSourceUtils.getConnection(dataSource);
+                    CommonFenceDO commonFenceDO = 
COMMON_FENCE_DAO.queryCommonFenceDO(conn, xid, branchId);
+                    // non_rollback
+                    if (commonFenceDO == null) {
+                        boolean result = insertCommonFenceLog(conn, xid, 
branchId, actionName, CommonFenceConstant.STATUS_SUSPENDED);
+                        LOGGER.info("Insert common fence record result: {}. 
xid: {}, branchId: {}", result, xid, branchId);
+                        if (!result) {
+                            throw new 
CommonFenceException(String.format("Insert common fence record error, rollback 
fence method failed. xid= %s, branchId= %s", xid, branchId),
+                                    FrameworkErrorCode.InsertRecordError);
+                        }
                         return true;
+                    } else {
+                        if (CommonFenceConstant.STATUS_ROLLBACKED == 
commonFenceDO.getStatus() || CommonFenceConstant.STATUS_SUSPENDED == 
commonFenceDO.getStatus()) {
+                            LOGGER.info("Branch transaction had already 
rollbacked before, idempotency rejected. xid: {}, branchId: {}, status: {}", 
xid, branchId, commonFenceDO.getStatus());
+                            return true;
+                        }
+                        if (CommonFenceConstant.STATUS_COMMITTED == 
commonFenceDO.getStatus()) {
+                            if (LOGGER.isWarnEnabled()) {
+                                LOGGER.warn("Branch transaction status is 
unexpected. xid: {}, branchId: {}, status: {}", xid, branchId, 
commonFenceDO.getStatus());
+                            }
+                            return false;
+                        }
                     }
-                    if (CommonFenceConstant.STATUS_COMMITTED == 
commonFenceDO.getStatus()) {
-                        if (LOGGER.isWarnEnabled()) {
-                            LOGGER.warn("Branch transaction status is 
unexpected. xid: {}, branchId: {}, status: {}", xid, branchId, 
commonFenceDO.getStatus());
+                    boolean result = updateStatusAndInvokeTargetMethod(conn, 
rollbackMethod, targetTCCBean, xid, branchId, 
CommonFenceConstant.STATUS_ROLLBACKED, status, args);
+                    LOGGER.info("Common fence rollback result: {}. xid: {}, 
branchId: {}", result, xid, branchId);
+                    return result;
+                } catch (Throwable t) {
+                    status.setRollbackOnly();
+                    Throwable cause = t.getCause();
+                    if (cause != null && cause instanceof SQLException) {
+                        SQLException sqlException = (SQLException) cause;
+                        String sqlState = sqlException.getSQLState();
+                        int errorCode = sqlException.getErrorCode();
+                        if ("40001".equals(sqlState) && errorCode == 1213) {
+                            // MySQL deadlock exception
+                            LOGGER.error("Common fence rollback fail. xid: {}, 
branchId: {}, This exception may be due to the deadlock caused by the 
transaction isolation level being Repeatable Read. The seata server will try to 
roll back again, so you can ignore this exception. (To avoid this exception, 
you can set transaction isolation to Read Committed.)", xid, branchId);
                         }
-                        return false;
                     }
+                    throw new SkipCallbackWrapperException(t);
+                } finally {
+                    RootContext.unbindTccLocalTxActive();
+                }
+            });
+        }
+    }
+
+    /**
+     * Check whether the transaction has been activated
+     * @return boolean
+     */
+    public static boolean isTransactionActive() {
+        return TransactionSynchronizationManager.isActualTransactionActive();
+    }
+
+    /**
+     * Check that the business method's transaction interceptor precedes the 
target interceptor
+     * @param method business method
+     * @param proxy proxy
+     * @param targetInterceptorClass the target interceptor class
+     * @return boolean
+     */
+    public static boolean hasTransactionAspectBeforeInterceptor(Method method, 
Object proxy, Class<?> targetInterceptorClass) {

Review Comment:
   为什么不在代理bean的时候就初始化好一切信息?
   Why not initialize everything in the proxy bean?



##########
integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/ActionInterceptorHandler.java:
##########
@@ -42,6 +34,14 @@
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
 
+import javax.annotation.Nonnull;

Review Comment:
   java的包应该在顶层
   Java packages should be at the top level



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org
For additional commands, e-mail: notifications-h...@seata.apache.org

Reply via email to