package com.easyooo.framework.sharding.transaction; import java.util.Iterator; import java.util.Map; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.HeuristicCompletionException; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.UnexpectedRollbackException; import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationUtils; /** * 一阶段模式事务管理链,代理获取到所有数据源管理器,链式提交事务,在最后提交事务 * * @author Killer */ public class ChainedTransactionManager implements PlatformTransactionManager{ Logger logger = LoggerFactory.getLogger(getClass()); @Override public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { if(logger.isDebugEnabled()){ logger.debug("Open a one-pc transaction."); } RoutingSynchronizationManager.initSynchronization(definition); return newTransactionStatus(definition, new TransactionObject()); } /** * Create a rae TransactionStatus instance for the given arguments. */ protected DefaultTransactionStatus newTransactionStatus( TransactionDefinition definition, Object transaction) { // Cache debug flag to avoid repeated checks. boolean debugEnabled = logger.isDebugEnabled(); return new DefaultTransactionStatus( transaction, true, true, definition.isReadOnly(), debugEnabled, null); } @Override public void commit(TransactionStatus status) throws TransactionException { if(logger.isDebugEnabled()){ logger.debug("Commit all connected transactions."); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status; try{ TransactionSynchronizationUtils.triggerBeforeCommit(defStatus.isReadOnly()); TransactionSynchronizationUtils.triggerBeforeCompletion(); Map<DataSource, ConnectionHolder> connSet = RoutingSynchronizationManager.getSynchronizations(); boolean commit = true; Exception commitException = null; ConnectionHolder commitExceptionConnection = null; for (ConnectionHolder connection : connSet.values()) { if (commit) { try { connection.commit(); if (logger.isDebugEnabled()) { logger.debug("Connection["+ connection +"] has been commited."); } } catch (Exception ex) { commit = false; commitException = ex; commitExceptionConnection = connection; } } else { try { connection.rollback(); if (logger.isDebugEnabled()) { logger.debug("Connection["+ connection +"] has been rolled back."); } } catch (Exception ex) { logger.warn("Rollback exception (after commit) (" + connection + ") " + ex.getMessage(), ex); } } } if (commitException != null) { boolean firstTransactionManagerFailed = (commitExceptionConnection == getLastConnectionHolder(connSet)); int transactionState = firstTransactionManagerFailed ? HeuristicCompletionException.STATE_ROLLED_BACK : HeuristicCompletionException.STATE_MIXED; throw new HeuristicCompletionException(transactionState, commitException); } }finally{ RoutingSynchronizationManager .invokeAfterCompletion(TransactionSynchronization.STATUS_COMMITTED); RoutingSynchronizationManager.clearSynchronization(); } } @Override public void rollback(TransactionStatus status) throws TransactionException { if(logger.isWarnEnabled()){ logger.warn("Rollback all connected transactions."); } try{ TransactionSynchronizationUtils.triggerBeforeCompletion(); Map<DataSource, ConnectionHolder> connSet = RoutingSynchronizationManager.getSynchronizations(); Exception rollbackException = null; ConnectionHolder rollbackExceptionConnection = null; for (ConnectionHolder connection:connSet.values()) { try { connection.rollback(); if (logger.isDebugEnabled()) { logger.debug("Connection["+ connection +"] has been rolled back."); } } catch (Exception ex) { if (rollbackException == null) { rollbackException = ex; rollbackExceptionConnection = connection; } else { logger.warn("Rollback exception (" + rollbackExceptionConnection + ") " + ex.getMessage(), ex); } } } if (rollbackException != null) { throw new UnexpectedRollbackException("Rollback exception, originated at ("+rollbackExceptionConnection+") "+ rollbackException.getMessage(), rollbackException); } }finally{ RoutingSynchronizationManager .invokeAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); RoutingSynchronizationManager.clearSynchronization(); } } private ConnectionHolder getLastConnectionHolder(Map<DataSource, ConnectionHolder> connSet) { if(connSet.size() != 0){ int lastConnectionIndex = connSet.size() - 1; Iterator<ConnectionHolder> ite = connSet.values().iterator(); for (int i = 0; ite.hasNext(); i++) { ConnectionHolder conn = ite.next(); if(i == lastConnectionIndex){ return conn; } } } return null; } public static class TransactionObject{ // Empty Object } }