package com.easyooo.framework.sharding.transaction; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.NamedThreadLocal; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationUtils; import org.springframework.util.Assert; /** * 多数据同步管理器,将一些上下文绑定到ThreadLocal * * @author Killer */ public abstract class RoutingSynchronizationManager { static Logger logger = LoggerFactory.getLogger(RoutingSynchronizationManager.class); private static final ThreadLocal<LinkedHashMap<DataSource, ConnectionHolder>> synchronizations = new NamedThreadLocal<LinkedHashMap<DataSource, ConnectionHolder>>("Transactional synchronizations"); private static final ThreadLocal<TransactionDefinition> definitions = new NamedThreadLocal<TransactionDefinition>("Transactional definition"); public static TransactionDefinition getCurrentTransactionDefinition(){ if (!isSynchronizationActive()) { throw new IllegalStateException("Transaction synchronization is not active"); } return definitions.get(); } public static boolean isSynchronizationActive() { return (synchronizations.get() != null); } public static void initSynchronization(TransactionDefinition definition) throws IllegalStateException { if (isSynchronizationActive()) { throw new IllegalStateException("Cannot activate transaction synchronization - already active"); } if(logger.isDebugEnabled()){ logger.debug("Initializing transaction synchronization"); } synchronizations.set(new LinkedHashMap<DataSource, ConnectionHolder>()); definitions.set(definition); // 初始化Spring同步事务管理器,这使得Mybatis让Spring接管事务时,有一个判断标准, // 不会重复打开Session,也不会直接关闭Session // 具体请参看 org.mybatis.spring.SqlSessionUtils#getSqlSession // org.mybatis.spring.SqlSessionTemplate.SqlSessionInterceptor#invoke TransactionSynchronizationManager.initSynchronization(); } public static void registerSynchronization(DataSource dataSource, ConnectionHolder connection) throws IllegalStateException { Assert.notNull(connection, "connection must not be null"); if (!isSynchronizationActive()) { throw new IllegalStateException("Transaction synchronization is not active"); } synchronizations.get().put(dataSource, connection); } public static Map<DataSource, ConnectionHolder> getSynchronizations() throws IllegalStateException { Map<DataSource,ConnectionHolder> synchs = synchronizations.get(); if (synchs == null) { throw new IllegalStateException("Transaction synchronization is not active"); } if (synchs.isEmpty()) { return Collections.emptyMap(); } return synchs; } public static void clearSynchronization() throws IllegalStateException { if (!isSynchronizationActive()) { throw new IllegalStateException("Cannot deactivate transaction synchronization - not active"); } if(logger.isDebugEnabled()){ logger.debug("Transaction cleaning."); } try{ Map<DataSource,ConnectionHolder> synchs = synchronizations.get(); List<SQLException> exceptions = new ArrayList<SQLException>(); for (ConnectionHolder connection : synchs.values()) { try { connection.close(); } catch (SQLException e) { exceptions.add(e); } } if(!exceptions.isEmpty()){ for (SQLException sqlException : exceptions) { logger.error("Close the connection error", sqlException); } } }finally{ synchronizations.remove(); definitions.remove(); // Clean up the Spring transaction synch TransactionSynchronizationManager.clear(); } } public static void invokeAfterCompletion(int completionStatus) { List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager .getSynchronizations(); TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus); } }