java.lang.Object
org.springframework.transaction.support.TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager
extends Object
Central helper that manages resourcesand transaction synchronizations per thread.
為每個線程管理資源和事務的中心helper
hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext時,
@Transactional,Spring的事務管理器HibernateTransactionManager.doBegin()方法開啟的Session和事務 就是綁定到TransactionSynchronizationManager的上下文(ThreadLocal的Map)中的。
SpringSessionContext.currentSesssion()方法就是在TransactionSynchronizationManager的上下文中查找session。
配置:
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 注解驅動:解析@Transactional注解,對@Transactional注解的方法用指定的事務管理器實作事務管理 -->
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
上文回顧:
現在對于hibernate.current_session_context_class= org.springframework.orm.hibernate4.SpringSessionContext時的getCurrentSession()就很清楚了:
1:@Transactional聲明的方法執行時,Spring的TransactionManager會自動Open Sesion,自動開啟事務,并且将此Sesion綁定到SpringSessionContext(實際上是TransactionSynchronizationManager的上下文中)中。
2:SessionFactory.getCurrentSession()方法執行時,調用SpringSessionContext.currentSession()從TransactionSynchronizationManager的上下文中查找 目前的Session。
3:找到後傳回目前的Session,找不到,則傳回HibernateException("No Session found for current thread")
spring 的事務管理架構:
1.接口:PlatformTransactionManager。
該接口隻有三個方法:
(1)TransactionStatus getTransaction(TransactionDefinition definition)
該方法的作用是:依據指定的事務定義傳回目前存在的事務或者是建立一個新的事務。這是入口。
(2)void commit(TransactionStatus status)
(3)void rollback(TransactionStatus status)
2.抽象類:public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable
該抽象類實作了接口PlatformTransactionManager定義的getTransaction(TransactionDefinition definition) 方法,并且是final類型的方法,
這就意味着具體的實作類都是用這個方法擷取事務的。方法内部調用doGetTransaction()方法用以擷取目前存在的事務,若是目前存在事務則取出并且依據指定的事務傳播行為處理。這個方法是抽象的,交給具體的事務管理器實作。若是目前不存在事務,則調用doBegin()方法建立一個事務并且綁定到TransactionSynchronizationManager的上下文(ThreadLocal的Map)中,綁定到目前線程。doBegin()方法也是抽象的,交給具體的事務管理器實作。
3.具體的事務管理器:
public class HibernateTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean
HibernateTransactionManager 實作了抽象類中的doGetTransaction()和doBegin()方法。
上述第一點是未驗證的,現在我們來分析一下源代碼:
[java] view plain copy
- Public UserService
- {
- @Transactional
- public void addUser(User user) throwsException
- {
- Session session =sessionFactory.getCurrentSession();
- session.save(user);
- }
- }
[java] view plain copy
- //當然,聲明式事務管理實質也是用AOP實作的,此時取得的一個Proxy..
- UserService userService = (UserService) beanFactory.getBean("userService");
- User user = new User();
- user.setName("Mark");
- userService.addUser(user); //在執行這一句時,應該是調用Proxy來開啟一個事務,并綁定到某個上下文中,我們跟進去看看
先進入到JdkDynamicAopProxyimplements.invoke()方法
然後到ReflectiveMethodInvocation. proceed(),這裡調用TransactionInterceptor.invoke(this)方法:
典型的攔截器模式:
1:按需開啟事務
2:遞歸執行下一個攔截器 或 執行代理目标方法
3:送出事務
[java] view plain copy
- public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor,Serializable {
- public Object invoke(final MethodInvocationinvocation) throws Throwable {
- .......
- //就在這一句開啟事務
- TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr,joinpointIdentification);
- ......
- retVal= invocation.proceed(); //執行下一個攔截器 或 執行代理目标的方法
- ...... //送出事務
- commitTransactionAfterReturning(txInfo);
- return retVal;
- .......
- }
- }
進入createTransactionIfNecessary(tm,txAttr, joinpointIdentification), 其中的tm.getTransaction(txAttr); //這一句應該是取得事務的,跟進去
……………………………………….
AbstractPlatformTransactionManager.getTransaction()方法:
如果目前有事務,取出并根據事務傳播行為的配置去處理,如果目前沒有事務,調用doBegin開啟一個新事務
[java] view plain copy
- public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
- ......
- public final TransactionStatus getTransaction(TransactionDefinitiondefinition) throws TransactionException {
- //這裡是取得目前已綁定到TransactionSynchronizationManager的上下文的事務,主要為事務傳播行為而設
- Object transaction =doGetTransaction();
- ........
- //如果事務已存在,根據事務傳播行為來處理,
- if(isExistingTransaction(transaction)) {
- // Existingtransaction found -> check propagation behavior to find out how to behave.
- return handleExistingTransaction(definition, transaction, debugEnabled);
- }
- ......
- //這裡最關鍵,開啟一個新的事務,并放進TransactionSynchronizationManager的上下文中,并綁定到目前線程)
- doBegin(transaction,definition);
- return status;
- .......
- }
- ......
- }
HibernateTransactionManager.doGetTransaction()方法:
嘗試擷取目前已綁定到TransactionSynchronizationManager的上下文的事務,主要為事務傳播行為而設
[java] view plain copy
- public class HibernateTransactionManager extends AbstractPlatformTransactionManager
- implements ResourceTransactionManager, InitializingBean {
- protected Object doGetTransaction() {
- HibernateTransactionObject txObject = new HibernateTransactionObject();
- ......
- //在TransactionSynchronizationManager的上下文中查找目前的Session(實質上也是與線程綁定的)
- SessionHolder sessionHolder =
- (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
- ......
- return txObject;
- }
- }
HibernateTransactionManager.doBegin()方法:
開啟一個新的事務,并放進TransactionSynchronizationManager的上下文(ThreadLocal的Map)中,綁定到目前線程)
[java] view plain copy
- public class HibernateTransactionManager extends AbstractPlatformTransactionManager
- implements ResourceTransactionManager, InitializingBean {
- ......
- protected void doBegin(Object transaction, TransactionDefinition definition) {
- HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
- .........
- try {
- if (txObject.getSessionHolder() == null || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
- //這裡才真正的打開Session
- Session newSession = SessionFactoryUtils.openSession(getSessionFactory());
- .........
- }
- session = txObject.getSessionHolder().getSession();
- .........
- Transaction hibTx;
- // Register transaction timeout.
- .........
- if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
- .........
- }
- else {
- //這裡才真正地開啟事務
- hibTx = session.beginTransaction();
- }
- .........
- //如果這新開啟的Session,則将SessionHolder(Session和Transaction)放到TransactionSynchronizationManager的上下文中(綁定到目前線程)
- // Bind the session holder to the thread.
- if (txObject.isNewSessionHolder()) {
- //以鍵值對<SessionFactory,SessionHolder>形式綁定到TransactionSynchronizationManager的上下文中
- TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
- }
- .......
- }
- .........
- }
- ......
- }
Spring @Transactional 如何開啟事務 總結:
@Transactional聲明的方法執行時會調用AbstractPlatformTransactionManager.getTransaction()取得目前事務。
而getTransaction()的執行流程如下:
1:嘗試擷取目前已綁定到TransactionSynchronizationManager的上下文的事務
(調用HibernateTransactionManager.doGetTransaction()方法)
2:如果取得已存在的事務,則根據事務傳播屬性的設定來處理
(調用AbstractPlatformTransactionManager.handleExistingTransaction()方法)
3:如果沒有事務,則打開新的Session,開啟新的事務,并将該Session和事務綁定到TransactionSynchronizationManager的上下文中(調用HibernateTransactionManager.doBegin()方法)
-------------------------------------------------
核心還是了解TransactionSynchronizationManager,要懂得Spring的TransactionManager開啟事務後是以鍵值對<SessionFactory,SessionHolder>形式 存放到 TransactionSynchronizationManager的上下文(ThreadLocal的Map)中(以ThreadLocal的方式與目前線程綁定).