問題:web 一.spring 1. Spring 如何處理propagation=Propagation.SUPPORTS?sql 2. Spring 什麼時候生成HibernateSession ?數據庫 3. propagation=Propagation.SUPPORTS 和propagation=Propagation.require對生成Session有何影響 ?編程 共同點:都會進入aspect切面處理, 試圖新建Session,開啓Transaction ,都能得到.TransactionStatus session 區別: 前者成功開啓事務,後者未開啓,但會設置一個容許懶惰加載Session的配置.詳情見下面代碼.app 3.1. 未配置@Transaction 和 配置@Transaction(propagation=Propagation.SUPPORTS)的區別?工具 共同點: 都沒有起事務.ui 不一樣點: 前者不會進入aspect切面處理, 後者進入試圖新建Session,開啓事務但未成功,會設置一個容許懶惰加載Session的配置. 詳情見下面代碼spa 4. Spring 什麼時候從線程池中獲取到 jdbcconnection 設置 setAutoCommit(false)?
|
正文解析: spring是在TransactionAspectSupport(切面編程)的createTransactionIfNecessary方法中完成對@Transactional註解的處理. 而後委託給PlatformTransactionManager實現類的getTransaction()方法( 實現 類是HibernateTransactionManager被咱們配置在application.xml中)對propagation=Propagation.SUPPORTS的處理也是在這個方法內實現,具體是其父類AbstractPlatformTransactionManager.getTransaction()中. 代碼片斷以下: AbstractPlatformTransactionManager.getTransaction(TransactionDefinitiondefinition){ Object transaction = doGetTransaction(); //注1: springframework的HibernateTransactionObject 實例,內部持有的是 HibernateSession ,一開始是Null; . . otherCode . . // No existing transaction found -> check propagationbehavior to find out how to proceed. if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transactionmarked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior()== TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() ==TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null); if (debugEnabled) { logger.debug("Creating new transaction withname [" + definition.getName() + "]:" + definition); } try { boolean newSynchronization =(getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true,newSynchronization, debugEnabled, suspendedResources); doBegin(transaction, definition); // 注2: 生成 HibernateSession ,而後獲取jdbcconnection , 而且Connection,setAutoCommit(false),開啓咱們理解上的sql事務.具體是調用Session持有的HibernateJDBCTransaction中的.begin()方法中, prepareSynchronization(status,definition); //設置SpringTransactionSynchronizationManager.initSynchronization(). return status; } catch (RuntimeException ex) { resume(null, suspendedResources); throw ex; } catch (Error err) { resume(null, suspendedResources); throw err; } } else { // 注3 這個流程就是當」線程中無事務,且配置是propagation= Propagation.SUPPORTS」時執行的路徑.這一步未生成Hibernate Session, jdbc Connection.但 prepareTransactionStatus()中作了一步操做,設置SpringTransactionSynchronizationManager.initSynchronization().正是這個操做在以後,咱們 才能在後來Hibernate save or update時,容許Hibernate 回調初始化時註冊的 Spring SpringSessionContext 生成 HibernateSession ,進一步從鏈接池獲取 jdbcConnection // Create "empty" transaction: no actualtransaction, but potentially synchronization. boolean newSynchronization = (getTransactionSynchronization()== SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true,newSynchronization, debugEnabled, null); } . . . } 注2和注3解答了2,3問題. 對以上代碼中命名的一點見解: l getTransaction返回TransactioStaus, 感受用 getTransactioStaus比 spring目前的命名getTransaction更合適 或者取名 getTransactionIfNecessary比較好的,根據注3可知,此分支並無真正的開啓數據庫事務.更沒有獲取jdbc Connection.和任何生成 Hibernate Session. l 比較重要的幾個類Springframework的HibernateTransactionObject,Hibernate的Session,Hibernate的JDBCTransaction,jdbc的Connection. Springframework HibernateTransactionObject持有一個 Hibernate Session, Hibernate Session持有一個Hibernate JDBCTransaction , 最終持有 jdbc Connection. 由於 數據庫事務Connection.setAutoCommit(false).事務開啓是附屬於Connection. Connection應該是先於事務開啓. 因此感受用Springframework HibernateTransactionObject 和Hibernate JDBCTransaction 持有 jdbc Connection不一樣合理. 取名爲 Springframework HibernateTransactionStatusObject , Hibernate JDBCTransactionStaus更合理.
對於第4個問題. 對於@Transaction(propagation=Propagation.REQUIRE)時 Session新建和Session獲取都是在AbstractPlatformTransactionManager.getTransaction方法中完成的 對於@Transaction(propagation=Propagation.SUPPORTS) , 當懶惰獲取完Session後,當且僅當真正嘗試數據庫操做時纔會懶惰獲取Connection. 獲取Connection的簡單堆棧以下. ConnectionManager.openConnection()line: 446 //注:發現沒有鏈接,從線程池獲取一個鏈接 ConnectionManager.getConnection()line: 167 BatchingBatcher(AbstractBatcher).prepareQueryStatement(String,boolean, ScrollMode) line: 161 EntityLoader(Loader).prepareQueryStatement(QueryParameters,boolean, SessionImplementor) line: 1700
|
問題: 二. 對於上面第3個小問題的延伸,注3代表此處並無生成Session. 而後get or save 正常不報錯. 咱們定義爲A狀況. A.當處於propagation=Propagation.SUPPORTS時,未生成Session和獲取到jdbc Connection.當咱們 save or get 時候正常不報錯. 下面看下無Session狀況下獲取Session的另一種狀況: B.咱們可能遇到過這樣的錯誤:No Hibernate Session bound to thread,and configuration does not allow creationof non-transactional one here.錯誤緣由是咱們save or get的時候獲取不到Session,不正常拋錯 A和B都是在無Session狀況下獲取Session, 爲何一個正常,一個不正常?
|
正文解析: 具體代碼片斷以下: SpringSessionFactoryUtils.doGetSession(SessionFactory sessionFactory,InterceptorentityInterceptor,SQLExceptionTranslator jdbcExceptionTranslator,booleanallowCreate){ if (TransactionSynchronizationManager.isSynchronizationActive()){ // 注4:A狀況下返回是true,緣由見注3,B狀況下返回是false. // 注: 此部分代碼實現了」若是目前沒有Session那麼就生成Session」的邏輯 } if ((!(allowCreate)) && (!(isSessionTransactional(session,sessionFactory)))) { // 注5: 兩個開關判斷.allowCreate 對於HibernateManager是強制設置爲false(關閉)的,後者正是前面HibernateManager處理@Transaction時開啓(返回true). 有一個容許就正常執行返回了Session. 兩個有一個開啓(ture)就不拋錯,正常執行返回Session. 什麼時候allowCreate是ture?見下面 三. 那麼什麼時候能夠獲取非事務類型的Session? . closeSession(session); throw new IllegalStateException("No Hibernate Session bound to thread, andconfiguration does not allow creation of non-transactional one here"); } return session; //注6, 若是沒有被注5禁止,那麼就返回生成的Session } 注4,注5解答了上述問題. 因此出現B問題, 檢查下本身的代碼,是否處於事務環境中. 因爲getTransaction()會把Session綁定到ThreadLocal中,若是新建了獨立線程, 注意內部調用的代碼是否加上@Transaction,否則該線程中是沒法獲取到Threadlocal的Session變量. 對於這個Exception.後半部分」configuration does notallow creation of non-transactional one here」的具體語義.是指」configuration不容許生成一個非事務類型的Session」. |
三. 那麼什麼時候能夠獲取非事務類型的Session? |
1. 查看源代碼能夠發現OpenSessionInViewFilter中能夠 (配置在 web.xml中),正是這個allow=true ,才使其在無事務環境下先生成一個Session,並延遲關閉.保證了view層可以獲取到懶惰加載的實體. 2. 還有就是Spring 提供的HibernateTemplate 模板工具類中也是allow=true,方便咱們執行Hibernate方法.
其餘如propagation= Propagation.require_new也是在上述的代碼中,進行原connection掛起和恢復的操做.具體詳見代碼.
|
其餘如propagation =Propagation.require_new也是在上述的代碼中,進行原connection掛起和恢復的操做.具體詳見代碼.
原文地址:http://blog.csdn.net/fei33423/article/details/32346821