Open Session and Hibernate事物處理機制

在沒有使用Spring提供的Open Session In View情況下,因需要在service(or Dao)層裏把session關閉,所以lazy loading 爲true的話,要在應用層內把關係集合都初始化,如 company.getEmployees(),否則Hibernate拋session already closed Exception;    Open Session In View提供了一種簡便的方法,較好地解決了lazy loading問題.    
    它有兩種配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具體參看SpringSide),功能相同,只是一個在web.xml配置,另一個在application.xml配置而已。    
     Open Session In View在request把session綁定到當前thread期間一直保持hibernate session在open狀態,使session在request的整個期間都可以使用,如在View層裏PO也可以lazy loading數據,如 ${ company.employees }。當View 層邏輯完成後,纔會通過Filter的doFilter方法或Interceptor的postHandle方法自動關閉session。
     OpenSessionInViewInterceptor配置
Xml代碼  收藏代碼
  1.     
  2. <beans>   
  3. <bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">   
  4. <property name="sessionFactory">   
  5. <ref bean="sessionFactory"/>   
  6. </property>   
  7. </bean>   
  8. <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">   
  9. <property name="interceptors">   
  10. <list>   
  11. <ref bean="openSessionInViewInterceptor"/>   
  12. </list>   
  13. </property>   
  14. <property name="mappings">   
  15. ...   
  16. </property>   
  17. </bean> ... </beans>   

OpenSessionInViewFilter配置
Xml代碼  收藏代碼
  1.    
  2. <web-app>   
  3. ...   
  4. <filter>   
  5. <filter-name>hibernateFilter</filter-name>   
  6. <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class>   
  7. <!-- singleSession默認爲true,若設爲false則等於沒用OpenSessionInView -->   
  8. <init-param>   
  9. <param-name>singleSession</param-name>   
  10. <param-value>true</param-value>   
  11. </init-param>   
  12. </filter> ... <filter-mapping>   
  13. <filter-name>hibernateFilter</filter-name>   
  14. <url-pattern>*.do</url-pattern>   
  15. </filter-mapping> ... </web-app>   

    很多人在使用OpenSessionInView過程中提及一個錯誤:
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
    看看OpenSessionInViewFilter裏的幾個方法
Java代碼  收藏代碼
  1.     
  2.   
  3. protected void doFilterInternal(HttpServletRequest request,   
  4.         HttpServletResponse response,  
  5.         FilterChain filterChain) throws ServletException, IOException {   
  6.         SessionFactory sessionFactory = lookupSessionFactory();   
  7.         logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");   
  8.         Session session = getSession(sessionFactory);   
  9.         TransactionSynchronizationManager.bindResource(    
  10.                 sessionFactory, new SessionHolder(session));   
  11.         try {    
  12.             filterChain.doFilter(request, response);   
  13.             }   
  14.         finally {   
  15.             TransactionSynchronizationManager.unbindResource(sessionFactory);   
  16.         logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");   
  17.         closeSession(session, sessionFactory);   
  18.         }  
  19. }   
  20. protected Session getSession(SessionFactory sessionFactory)  
  21.                    throws DataAccessResourceFailureException {   
  22.         Session session = SessionFactoryUtils.getSession(sessionFactory, true);   
  23.         session.setFlushMode(FlushMode.NEVER);   
  24.         return session;  
  25. }  
  26. protected void closeSession(Session session,   
  27.         SessionFactory sessionFactory)throws CleanupFailureDataAccessException {   
  28.     SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);  
  29. }  
  

protected void doFilterInternal(HttpServletRequest request, 
		HttpServletResponse response,
		FilterChain filterChain) throws ServletException, IOException { 
	    SessionFactory sessionFactory = lookupSessionFactory(); 
		logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); 
		Session session = getSession(sessionFactory); 
		TransactionSynchronizationManager.bindResource(  
				sessionFactory, new SessionHolder(session)); 
		try {  
			filterChain.doFilter(request, response); 
			} 
		finally { 
			TransactionSynchronizationManager.unbindResource(sessionFactory); 
		logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); 
		closeSession(session, sessionFactory); 
		}
} 
protected Session getSession(SessionFactory sessionFactory)
                   throws DataAccessResourceFailureException { 
		Session session = SessionFactoryUtils.getSession(sessionFactory, true); 
		session.setFlushMode(FlushMode.NEVER); 
		return session;
}
protected void closeSession(Session session, 
		SessionFactory sessionFactory)throws CleanupFailureDataAccessException { 
	SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);
}

     關於綁定session的方式,通過看spring裏TransactionSynchronizationManager的實現,發現:它維護一個 java.lang.ThreadLocal類型的resources,resources負責持有線程局部變量,這裏resources持有的是一個 HashMap,通過TransactionSynchronizationManager.bindResource()方法在map裏綁定和線程相關的所有變量到他們的標識上,包括如上所述的綁定在sessionFactory上的線程局部session。sessionHolder只不過是存放可以 hold一個session並可以和transtaction同步的容器。可以看到 OpenSessionInViewFilter在getSession的時候,會把獲取回來的session的flush mode 設爲FlushMode.NEVER。然後把該sessionFactory綁定到 TransactionSynchronizationManager,使request的整個過程都使用同一個session,在請求過後再接除該 sessionFactory的綁定,最後closeSessionIfNecessary根據該session是否已和transaction綁定來決定是否關閉session。綁定以後,就可以防止每次不會新開一個Session呢?看看HibernateDaoSupport的情況:
Java代碼  收藏代碼
  1.    
  2. public final void setSessionFactory(SessionFactory sessionFactory) {   
  3. this.hibernateTemplate = new HibernateTemplate(sessionFactory);   
  4. }    
  5. rotected final HibernateTemplate getHibernateTemplate() {  
  6. return hibernateTemplate;    
  7.            
  
 public final void setSessionFactory(SessionFactory sessionFactory) { 
 this.hibernateTemplate = new HibernateTemplate(sessionFactory); 
 }  
protected final HibernateTemplate getHibernateTemplate() {
 return hibernateTemplate;  
}         

     我們的DAO將使用這個template進行操作.
Java代碼  收藏代碼
  1.      
  2. public abstract class BaseHibernateObjectDao   
  3.                 extends HibernateDaoSupportimplements BaseObjectDao {       
  4. protected BaseEntityObject getByClassId(final long id) {                  
  5. BaseEntityObject obj =(BaseEntityObject)getHibernateTemplate().execute(new HibernateCallback() {                          
  6. public Object doInHibernate(Session session)   
  7.          throws HibernateException{                                      
  8.  return session.get(getPersistentClass(),new Long(id));                  
  9.        }                  
  10.     }  
  11. );                  
  12. return obj;        
  13. }       
  14. public void save(BaseEntityObject entity) {                    
  15.        getHibernateTemplate().saveOrUpdate(entity);       
  16. }       
  17. public void remove(BaseEntityObject entity) {                
  18. try {                       
  19.        getHibernateTemplate().delete(entity);                
  20. catch (Exception e) {                        
  21.        throw new FlexEnterpriseDataAccessException(e);               
  22.        }        
  23. }         
  24. public void refresh(final BaseEntityObject entity) {                 
  25.        getHibernateTemplate().execute(new HibernateCallback(){                            
  26.             public Object doInHibernate(Session session)   
  27.            throws HibernateException   {                                  
  28.                  session.refresh(entity);                                        
  29.                  return null;                            
  30.             }                 
  31.        }  
  32.     );        
  33. }        
  34. public void replicate(final Object entity) {                  
  35.        getHibernateTemplate().execute(new HibernateCallback(){                            
  36.              public Object doInHibernate(Session session)  
  37.                            throws HibernateException{                                        
  38.                   session.replicate(entity,ReplicationMode.OVERWRITE);                   
  39.                   eturn null;                 
  40.              }                  
  41.       });        
  42.    }  
  43. }             
   
public abstract class BaseHibernateObjectDao 
                extends HibernateDaoSupportimplements BaseObjectDao {     
protected BaseEntityObject getByClassId(final long id) {                
BaseEntityObject obj =(BaseEntityObject)getHibernateTemplate().execute(new HibernateCallback() {                        
public Object doInHibernate(Session session) 
         throws HibernateException{                                    
 return session.get(getPersistentClass(),new Long(id));                
       }                
    }
);                
return obj;      
}     
public void save(BaseEntityObject entity) {                  
       getHibernateTemplate().saveOrUpdate(entity);     
}     
public void remove(BaseEntityObject entity) {              
try {                     
       getHibernateTemplate().delete(entity);              
} catch (Exception e) {                      
       throw new FlexEnterpriseDataAccessException(e);             
       }      
}       
public void refresh(final BaseEntityObject entity) {               
       getHibernateTemplate().execute(new HibernateCallback(){                          
            public Object doInHibernate(Session session) 
           throws HibernateException   {                                
                 session.refresh(entity);                                      
                 return null;                          
            }               
       }
    );      
}      
public void replicate(final Object entity) {                
       getHibernateTemplate().execute(new HibernateCallback(){                          
             public Object doInHibernate(Session session)
                           throws HibernateException{                                      
                  session.replicate(entity,ReplicationMode.OVERWRITE);                 
                  eturn null;               
             }                
      });      
   }
}           
   
   而HibernateTemplate試圖每次在execute之前去獲得Session,執行完就力爭關閉Session
Java代碼  收藏代碼
  1.     
  2. public Object execute(HibernateCallback action) throws DataAccessException {    
  3.        Session session = (!this.allowCreate)SessionFactoryUtils.getSession(getSessionFactory(),  
  4.                          false);       
  5.        SessionFactoryUtils.getSession(getSessionFactory(),  
  6.                                       getEntityInterceptor(),   
  7.                                       getJdbcExceptionTranslator()));       
  8.        boolean existingTransaction = TransactionSynchronizationManager.hasResource(  
  9.                                        getSessionFactory());     
  10.        if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {     
  11.             session.setFlushMode(FlushMode.NEVER);    
  12. }        
  13. try {            
  14.      Object result = action.doInHibernate(session);             
  15.      flushIfNecessary(session, existingTransaction);             
  16.      return result;      
  17. }      
  18. catch (HibernateException ex) {            
  19. throw convertHibernateAccessException(ex);       
  20. }       
  21. finally {       
  22.     SessionFactoryUtils.closeSessionIfNecessary(    
  23.     session, getSessionFactory());       
  24.     }   
  25. }         
  
public Object execute(HibernateCallback action) throws DataAccessException {  
       Session session = (!this.allowCreate)SessionFactoryUtils.getSession(getSessionFactory(),
                         false);     
       SessionFactoryUtils.getSession(getSessionFactory(),
                                      getEntityInterceptor(), 
                                      getJdbcExceptionTranslator()));     
       boolean existingTransaction = TransactionSynchronizationManager.hasResource(
                                       getSessionFactory());   
       if (!existingTransaction && getFlushMode() == FLUSH_NEVER) {   
            session.setFlushMode(FlushMode.NEVER);  
}      
try {          
     Object result = action.doInHibernate(session);           
     flushIfNecessary(session, existingTransaction);           
     return result;    
}    
catch (HibernateException ex) {          
throw convertHibernateAccessException(ex);     
}     
finally {     
    SessionFactoryUtils.closeSessionIfNecessary(  
    session, getSessionFactory());     
    } 
}       

   而這個SessionFactoryUtils能否得到當前的session以及closeSessionIfNecessary是否真正關閉 session,取決於這個session是否用sessionHolder和這個sessionFactory在我們最開始提到的 TransactionSynchronizationManager綁定。     
Java代碼  收藏代碼
  1.     
  2. public static void closeSessionIfNecessary(Session session,   
  3.                                            SessionFactory sessionFactory)   
  4.                 throws CleanupFailureDataAccessException {   
  5.    if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)) {   
  6.                return;   
  7. }   
  8.         logger.debug("Closing Hibernate session");   
  9. try {   
  10.         session.close();   
  11. catch (JDBCException ex) { // SQLException underneath  
  12.     throw new CleanupFailureDataAccessException("Could not close Hibernate session",   
  13.                                              ex.getSQLException());   
  14. catch (HibernateException ex) {   
  15.     throw new CleanupFailureDataAccessException("Could not close Hibernate session",   
  16.               ex);   
  17.        }   
  18. }       
  
public static void closeSessionIfNecessary(Session session, 
                                           SessionFactory sessionFactory) 
                throws CleanupFailureDataAccessException { 
   if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)) { 
               return; 
} 
        logger.debug("Closing Hibernate session"); 
try { 
        session.close(); 
} catch (JDBCException ex) { // SQLException underneath
    throw new CleanupFailureDataAccessException("Could not close Hibernate session", 
                                             ex.getSQLException()); 
} catch (HibernateException ex) { 
    throw new CleanupFailureDataAccessException("Could not close Hibernate session", 
              ex); 
       } 
}     

     在這個過程中,若HibernateTemplate 發現自當前session有不是readOnly的transaction,就會獲取到FlushMode.AUTO Session,使方法擁有權限。也即是,如果有不是readOnly的transaction就可以由Flush.NEVER轉爲 Flush.AUTO,擁有insert,update,delete操作權限,如果沒有transaction,並且沒有另外人爲地設flush model的話,則doFilter的整個過程都是Flush.NEVER。所以受transaction保護的方法有寫權限,沒受保護的則沒有。
     可能的解決方式有:
1、將singleSession設爲false,這樣只要改web.xml,缺點是Hibernate Session的Instance可能會大增,使用的JDBC Connection量也會大增,如果Connection Pool的maxPoolSize設得太小,很容易就出問題。
2、在控制器中自行管理Session的FlushMode,麻煩的是每個有Modify的Method都要多幾行程式。     
session.setFlushMode(FlushMode.AUTO);      
session.update(user);      
session.flush();
3、Extend OpenSessionInViewFilter,Override protected Session getSession(SessionFactory sessionFactory),將FlushMode直接改爲Auto。
4、讓方法受Spring的事務控制。這就是常使用的方法: 採用spring的事務聲明,使方法受transaction控制 
Xml代碼  收藏代碼
  1.      
  2. <bean id="baseTransaction" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"             
  3. abstract="true">           
  4. <property name="transactionManager" ref="transactionManager"/>           
  5. <property name="proxyTargetClass" value="true"/>           
  6. <property name="transactionAttributes">               
  7. <props>                   
  8. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>                   
  9. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>                   
  10. <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>                   
  11. <prop key="save*">PROPAGATION_REQUIRED</prop>                   
  12. <prop key="add*">PROPAGATION_REQUIRED</prop>                   
  13. <prop key="update*">PROPAGATION_REQUIRED</prop>                   
  14. <prop key="remove*">PROPAGATION_REQUIRED</prop>               
  15. </props>           
  16. </property>       
  17. </bean>       
  18. <bean id="userService" parent="baseTransaction">           
  19. <property name="target">               
  20. <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>           
  21. </property>       
  22. </bean>   

    對於上例,則以save,add,update,remove開頭的方法擁有可寫的事務,如果當前有某個方法,如命名爲importExcel(),則因沒有transaction而沒有寫權限,這時若方法內有insert,update,delete操作的話,則需要手動設置flush model爲Flush.AUTO,如 session.setFlushMode(FlushMode.AUTO); session.save(user); session.flush();      
    儘管Open Session In View看起來還不錯,其實副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代碼,這個方法實際上是被父類的doFilter調用的,因此,我們可以大約瞭解的OpenSessionInViewFilter調用流程: request(請求)->open session並開始transaction->controller->View(Jsp)->結束transaction並 close session.     
    一切看起來很正確,尤其是在本地開發測試的時候沒出現問題,但試想下如果流程中的某一步被阻塞的話,那在這期間connection就一直被佔用而不釋放。最有可能被阻塞的就是在寫Jsp這步,一方面可能是頁面內容大,response.write的時間長,另一方面可能是網速慢,服務器與用戶間傳輸時間久。當大量這樣的情況出現時,就有連接池連接不足,造成頁面假死現象。 Open Session In View是個雙刃劍,放在公網上內容多流量大的網站請慎用。   另外:這樣會產生一點危險性,畢竟把數據庫訪問的環境放到了表現層。(:用VO)                  
      Hibernate是對JDBC的輕量級對象封裝,Hibernate本身是不具備Transaction處理功能的,Hibernate的 Transaction實際上是底層的JDBC Transaction的封裝,或者是JTA Transaction的封裝,下面我們詳細的分析:   
      Hibernate可以配置爲JDBCTransaction或者是JTATransaction,這取決於你在hibernate.properties中的配置:
引用

#hibernate.transaction.factory_classnet.sf.hibernate.transaction.JTATransactionFactory #hibernate.transaction.factory_classnet.sf.hibernate.transaction.JDBCTransactionFactory
  
     如果你什麼都不配置,默認情況下使用JDBCTransaction,如果你配置爲:
引用
 
hibernate.transaction.factory_classnet.sf.hibernate.transaction.JTATransactionFactory

     將使用JTATransaction,不管你準備讓Hibernate使用JDBCTransaction,還是JTATransaction,我的忠告就是什麼都不配,將讓它保持默認狀態,如下:
引用
  
#hibernate.transaction.factory_classnet.sf.hibernate.transaction.JTATransactionFactory #hibernate.transaction.factory_classnet.sf.hibernate.transaction.JDBCTransactionFactory   

     在下面的分析中我會給出原因。   
一、JDBC Transaction   
     看看使用JDBC Transaction的時候我們的代碼例子:
Java代碼  收藏代碼
  1.     
  2. Session session = sf.openSession();   
  3. Transaction tx = session.beginTransactioin();   
  4. ... session.flush();   
  5. tx.commit();   
  6. session.close();     
  
Session session = sf.openSession(); 
Transaction tx = session.beginTransactioin(); 
... session.flush(); 
tx.commit(); 
session.close();   

     這是默認的情況,當你在代碼中使用Hibernate的Transaction的時候實際上就是JDBCTransaction。那麼JDBCTransaction究竟是什麼東西呢?來看看源代碼就清楚了:   Hibernate2.0.3源代碼中的類net.sf.hibernate.transaction.JDBCTransaction:
Java代碼  收藏代碼
  1.     
  2. public void begin() throws HibernateException {   
  3. ...   
  4. if (toggleAutoCommit) session.connection().setAutoCommit(false);   
  5. ...   
  6. }    
  
public void begin() throws HibernateException { 
... 
if (toggleAutoCommit) session.connection().setAutoCommit(false); 
... 
}  

     這是啓動Transaction的方法,看到 connection().setAutoCommit(false) 了嗎?是不是很熟悉?   
     再來看
Java代碼  收藏代碼
  1.      
  2. public void commit() throws HibernateException {   
  3. ...   
  4. try {   
  5.  if (   
  6.  session.getFlushMode()!=FlushMode.NEVER )   
  7. session.flush();   
  8. try {   
  9. session.connection().commit();   
  10. committed = true;   
  11. }   
  12. ...   
  13. toggleAutoCommit();   
  14. }     
   
public void commit() throws HibernateException { 
... 
try { 
 if ( 
 session.getFlushMode()!=FlushMode.NEVER ) 
session.flush(); 
try { 
session.connection().commit(); 
committed = true; 
} 
... 
toggleAutoCommit(); 
}   

     這是提交方法,看到connection().commit() 了嗎?下面就不用我多說了,這個類代碼非常簡單易懂,通過閱讀使我們明白Hibernate的Transaction都在幹了些什麼?我現在把用 Hibernate寫的例子翻譯成JDBC,大家就一目瞭然了:
Java代碼  收藏代碼
  1.      
  2. Connection conn = ...;                 
  3. <--- session = sf.openSession();   
  4. conn.setAutoCommit(false);     
  5. <--- tx = session.beginTransactioin();   
  6. ...   
  7. <--- ... conn.commit();                             
  8. <--- tx.commit();   
  9. (對應左邊的兩句) conn.setAutoCommit(true);   
  10. conn.close();                                
  11. <--- session.close();     
   
Connection conn = ...;               
<--- session = sf.openSession(); 
conn.setAutoCommit(false);   
<--- tx = session.beginTransactioin(); 
... 
<--- ... conn.commit();                           
<--- tx.commit(); 
(對應左邊的兩句) conn.setAutoCommit(true); 
conn.close();                              
<--- session.close();   

   看明白了吧,Hibernate的JDBCTransaction根本就是conn.commit而已,根本毫無神祕可言,只不過在Hibernate 中,Session打開的時候,就會自動conn.setAutoCommit(false),不像一般的JDBC,默認都是true,所以你最後不寫 commit也沒有關係,由於Hibernate已經把AutoCommit給關掉了,所以用Hibernate的時候,你在程序中不寫 Transaction的話,數據庫根本就沒有反應。 
二、JTATransaction
     如果你在EJB中使用Hibernate,或者準備用JTA來管理跨Session的長事務,那麼就需要使用JTATransaction,先看一個例子:
Java代碼  收藏代碼
  1.     
  2. javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction");   
  3. Session s1 = sf.openSession();   
  4. ...   
  5. s1.flush();   
  6. s1.close();   
  7. ...   
  8. Session s2 = sf.openSession();   
  9. ...  
  10. s2.flush();   
  11. s2.close();  
  12. tx.commit();   
  
javax.transaction.UserTransaction tx = new InitialContext().lookup("javax.transaction.UserTransaction"); 
Session s1 = sf.openSession(); 
... 
s1.flush(); 
s1.close(); 
... 
Session s2 = sf.openSession(); 
...
s2.flush(); 
s2.close();
tx.commit(); 

    這是標準的使用JTA的代碼片斷,Transaction是跨Session的,它的生命週期比Session要長。如果你在EJB中使用 Hibernate,那麼是最簡單不過的了,你什麼Transaction代碼統統都不要寫了,直接在EJB的部署描述符上配置某某方法是否使用事務就可以了。 現在我們來分析一下JTATransaction的源代碼,
net.sf.hibernate.transaction.JTATransaction:
Java代碼  收藏代碼
  1.      
  2. public void begin(InitialContext context,   
  3. ...   
  4. ...   
  5. ut = (UserTransaction) context.lookup(utName);   
  6. ...   
   
public void begin(InitialContext context, 
... 
... 
ut = (UserTransaction) context.lookup(utName); 
... 

    看清楚了嗎? 和我上面寫的代碼 “tx = new Initial Context?().lookup("javax.transaction.UserTransaction"); ”是不是完全一樣?
Java代碼  收藏代碼
  1.     
  2. public void commit()   
  3. ...   
  4. ...   
  5. if (newTransaction)   
  6. ut.commit();  
  7.  ...   
  
public void commit() 
... 
... 
if (newTransaction) 
ut.commit();
 ... 

    JTATransaction的控制稍微複雜,不過仍然可以很清楚的看出來Hibernate是如何封裝JTA的Transaction代碼的。 但是你現在是否看到了什麼問題? 仔細想一下,Hibernate Transaction是從Session中獲得的,tx = session.beginTransaction(),最後要先提交tx,然後再session.close,這完全符合JDBC的 Transaction的操作順序,但是這個順序是和JTA的Transactioin操作順序徹底矛盾的!!! JTA是先啓動Transaction,然後啓動Session,關閉Session,最後提交Transaction,因此當你使用JTA的 Transaction的時候,那麼就千萬不要使用Hibernate的Transaction,而是應該像我上面的JTA的代碼片斷那樣使用纔行。
    總結:
1、在JDBC上使用Hibernate 必須寫上Hibernate Transaction代碼,否則數據庫沒有反應。此時Hibernate的Transaction就是Connection.commit而已;
2、在JTA上使用Hibernate 寫JTA的Transaction代碼,不要寫Hibernate的Transaction代碼,否則程序會報錯;
3、在EJB上使用Hibernate 什麼Transactioin代碼都不要寫,在EJB的部署描述符裏面配置
|---CMT(Container Managed Transaction) |
|---BMT(Bean Managed Transaction) |
|----JDBC Transaction |
|----JTA Transaction        
    關於session
1.  servlet的session機制基於cookies,關閉瀏覽器的cookies則session失效即不能用網站的登錄功能。
2.  Hibernate Session.      
       1>. session 清理緩存時,按照以下順序執行SQL語句:            
session.save()的實體insert     
               實體的update            
               對集合的delete       
               集合元素的delete,update,insert            
               集合的insert            
session.delete()的先後,執行實體的delete       
       2>. 默認時,session在以下時間點清理緩存:               net.sf.hibernate.Transaction.commit():先清理緩存,再向數據庫提交事務Session.find()或iterate()時,若緩存中持久化對象的屬性發生了變化,就會先清緩存,以保證查詢結果正確         
        3>.  Session的commit()和flush()的區別:
flush()只執行SQL語句,不提交事務;commit()先調用flush(),再提交事務       
        4>.  Session.setFlushMode()用於設定清理緩存的時間點:
清理緩存的模式 Session的查詢方法 Session.commit() Session.flush() FlushMode.AUTO 清理清理清理 FlushMode.COMMIT 不清理清理清理 FlushMode.NEVER 不清理不清理清
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章