Spring 將 JDBC 的 Connection、Hibernate 的 Session 等訪問數據庫的連接或者會話對象統稱為資源,這些資源在同一時刻是不能多線程共享的 。 為了讓 DAO 或 Service 類可以實現單例模式, Spring 的事務同步管理類 org.springframework.transaction.support.TransactionSynchronizationManager 利用 ThreadLocal 為不同的事務線程提供了獨立的資源副本,并同時維護這些事務的配置屬性和運行狀態信息 。
Spring 框架為不同的持久化技術提供了一套從 TransactionSynchronizationManager 中獲取對應線程綁定資源的工具類,這些工具類都提供了可以獲取綁定當前線程資源的靜態方法:
持久化技術 | 線程綁定資源獲取工具 | 靜態方法 |
---|---|---|
Spring JDBC 或 MyBatis | org.springframework.jdbc.datasource.DataSourceUtils | public static Connection getConnection(DataSource dataSource) |
HibernateX.0 | org.springframework.orm.hibernateC.SessionFactoryUtils | public static Session getSession(SessionFactory sessionFactory, boolean allowCreate) |
JPA | org.springframework.orm.jpa.EntityManagerFactoryUtils | public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf) |
JDO | org.springframework.orm.jdo.PersistenceManagerFactoryUtils | public static PersistenceManager getPersistenceManager(PersistenceManagerFactory pmf, boolean allowCreate) |
某些場景下,可能無法使用 Spring 提供的模板類。這時,就必須通過操作底層持久化技術所提供的原生 API ,而這就需要通過這些工具類來獲取線程綁定的資源。如果直接從 DataSource 或 SessionFactory 中獲取資源,那么就無法讓數據操作參與到與本線程相關的事務環境,因為這些對象不能獲取和當前線程相關的資源。
TransactionSynchronizationManager 源碼如下:
public abstract class TransactionSynchronizationManager {private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);private static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<Map<Object, Object>>("Transactional resources");private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =new NamedThreadLocal<Set<TransactionSynchronization>>("Transaction synchronizations");private static final ThreadLocal<String> currentTransactionName =new NamedThreadLocal<String>("Current transaction name");private static final ThreadLocal<Boolean> currentTransactionReadOnly =new NamedThreadLocal<Boolean>("Current transaction read-only status");private static final ThreadLocal<Integer> currentTransactionIsolationLevel =new NamedThreadLocal<Integer>("Current transaction isolation level");private static final ThreadLocal<Boolean> actualTransactionActive =new NamedThreadLocal<Boolean>("Actual transaction active");...
}
復制代碼
事務線程成員變量 | 說明 |
---|---|
resources | Connection 或 Session 等資源 |
currentTransactionName | 事務名稱 |
currentTransactionReadOnly | 事務只讀狀態 |
currentTransactionIsolationLevel | 事務隔離級別 |
actualTransactionActive | 事務激活狀態 |
TransactionSynchronizationManager 將 Dao、Service 類中影響線程安全的所有 “ 狀態 ” 都統一抽取到該類中,并用 ThreadLocal 進行封裝,這樣一來, Dao (基于模板類或資源獲取工具類創建的 Dao )和 Service (采用 Spring 事務管理機制)就變成線程安全的對象啦 O(∩_∩)O~