`
soartju
  • 浏览: 248078 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【转】open session and Hibernate事务处理机制

阅读更多

转自http://www.iteye.com/topic/186068

 

在没有使用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 >    
  
<beans> 
<bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> 
<property name="sessionFactory"> 
<ref bean="sessionFactory"/> 
</property> 
</bean> 
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 
<property name="interceptors"> 
<list> 
<ref bean="openSessionInViewInterceptor"/> 
</list> 
</property> 
<property name="mappings"> 
... 
</property> 
</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 >    
 
<web-app> 
... 
<filter> 
<filter-name>hibernateFilter</filter-name> 
<filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> 
<!-- singleSession默认为true,若设为false则等于没用OpenSessionInView --> 
<init-param> 
<param-name>singleSession</param-name> 
<param-value>true</param-value> 
</init-param> 
</filter> ... <filter-mapping> 
<filter-name>hibernateFilter</filter-name> 
<url-pattern>*.do</url-pattern> 
</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 >    
   
<bean id="baseTransaction" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"           
abstract="true">         
<property name="transactionManager" ref="transactionManager"/>         
<property name="proxyTargetClass" value="true"/>         
<property name="transactionAttributes">             
<props>                 
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>                 
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>                 
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>                 
<prop key="save*">PROPAGATION_REQUIRED</prop>                 
<prop key="add*">PROPAGATION_REQUIRED</prop>                 
<prop key="update*">PROPAGATION_REQUIRED</prop>                 
<prop key="remove*">PROPAGATION_REQUIRED</prop>             
</props>         
</property>     
</bean>     
<bean id="userService" parent="baseTransaction">         
<property name="target">             
<bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>         
</property>     
</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 不清理不清理清

分享到:
评论

相关推荐

    Hibernate Session释放模式

    在处理大量数据或者长时间运行的事务时,合理地管理Session的生命周期至关重要,这就涉及到了Hibernate的Session释放模式。本文将深入探讨Hibernate Session的几种释放模式,以及它们在实际开发中的应用和优缺点。 ...

    Hibernate事务管理.

    综上所述,Hibernate事务管理涉及到如何有效地处理数据库操作,特别是在使用懒加载时。Open Session In View模式提供了一种解决方案,但同时也需要注意其可能带来的并发问题。正确理解和使用事务管理策略对于构建...

    hibernate中session的管理

    3. **Open Session in View (OSIV)**:在视图渲染阶段保持Session打开,以允许最后时刻的懒加载,但需要注意防止Session泄露。 总的来说,Hibernate中Session的管理是保证多线程环境下数据一致性的重要环节。...

    课程hibernate的事务和并发.pdf

    ThreadLocal变量可以绑定到处理请求的线程,使得代码能方便地访问Session,而事务上下文环境也可存储在ThreadLocal中,根据所选的事务划分机制进行管理。这种方式被称为ThreadLocal Session和Open Session in View...

    Open Session in View模式.PPT

    Open Session in View (OSIV) 模式是一种在基于Hibernate的Web应用程序中处理持久化数据的策略,它允许在视图层(例如JSP页面)中安全地访问延迟加载的对象,而无需担心Session已关闭的问题。以下是关于这个模式及其...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    Spring框架的延迟加载和声明式事务处理是两个关键特性,...通过合理地使用Open Session in View机制,可以解决延迟加载时Session关闭导致的问题,同时,声明式事务处理则简化了事务管理,提升了应用的效率和可扩展性。

    Open_Session_In_View详解.doc

    `Open Session In View`的主要作用是在Web请求的开始阶段打开`Hibernate session`,并在请求结束时自动关闭该session。这样做的好处在于,可以确保在整个请求处理过程中session始终处于可用状态,使得在视图(View)层...

    Hibernate中获取Session的两种方式代码示例

    Hibernate中获取Session的两种方式代码示例 Hibernate 是一个流行的基于Java的持久层框架,提供了对数据库的访问和操作。Session 是 Hibernate 中一个核心概念,负责管理应用程序与数据库之间的交互。获取 Session ...

    Hibernate 面试题

    4. **使用Hibernate session**:在操作数据时,需先调用`open()`打开Session,完成后及时调用`close()`关闭Session,以释放资源并让连接池回收连接。 5. **Integer与int映射的差异**:使用Integer作为映射类型,...

    Hibernate 手册 第一章 Hibernate入门

    使用`Session`的`beginTransaction()`、`commit()`和`rollback()`方法可以处理事务。理解事务边界和回滚规则对于确保数据一致性至关重要。 9. 第一次运行与优化 在实际使用中,可能会遇到缓存问题、性能瓶颈等。...

    集成spring的hibernate懒加载

    在Spring整合Hibernate的情况下,Session通常通过Transaction Management进行管理,比如使用`Open Session in View`(OSIV)模式或者基于注解的事务管理。 当你尝试在Controller层或者视图层访问懒加载的属性时,...

    hibernate3 api

    Session的openTransaction()方法用于开启事务,commit()和rollback()分别用于提交和回滚事务。 2. Transaction接口:处理数据库事务,确保数据的一致性。Transaction接口的begin()、commit()和rollback()方法分别...

    hibernate框架实例

    Hibernate 是一款强大的Java对象关系映射(ORM)框架,它极大地简化了数据库操作,使得开发者可以使用面向对象的方式来处理数据库事务,而无需关注底层的SQL语句。本实例旨在帮助初学者更好地理解Hibernate框架的...

    hibernate添加用户

    ### Hibernate添加用户知识点详解 #### 一、概述 在Java Web开发中,Hibernate作为一个流行的ORM...此外,Hibernate框架还提供了许多高级特性,如缓存机制、懒加载等,这些特性对于提高系统性能同样具有重要意义。

    hibernate源代码的zip文件

    Session是短暂的,每次数据库操作后应关闭,它提供了open、close、save、update、delete、flush、clear等方法,以及Criteria、HQL和SQL查询。 五、持久化操作 Hibernate支持对象的持久化操作,如增删改查。save()...

    深入学习hibernate

    文章涵盖了Hibernate的核心接口与类、标识符生成策略、对象生命周期管理、OSIV(Open Session In View)模式、泛型DAO模式、集合映射、组件映射、各种关联关系的映射(一对一、一对多、多对多)、Criteria查询、HQL...

    OSGI中Hibernate扩展在felix中的应用

    6. **SessionFactory**:SessionFactory是Hibernate的主要组件,负责创建Session。在OSGI中,可能需要在bundle的Activator中创建SessionFactory,并作为服务注册。 7. **Transactions Management**:在OSGI环境中,...

    hibernate3.0 核心代码

    在事务处理方面,Hibernate支持JTA(Java Transaction API)和JDBC事务。`Transaction`接口提供了开始、提交、回滚事务的方法,与数据库的事务管理无缝集成,确保了数据的一致性。 此外,Hibernate的事件监听和拦截...

    韩顺平.2011版.hibernate笔记.zip

    7. Criteria API与CGLIB代理:Hibernate在处理懒加载时会用到CGLIB代理,这部分内容可能会涉及到如何使用CGLIB和Hibernate结合,以实现透明的懒加载机制。 8. 集合映射与关联管理:Hibernate支持多种集合类型的映射...

    手动搭建Hibernate框架工程

    = null && session.isOpen()) { session.close(); } } } ``` 现在,你已经准备好使用Hibernate进行CRUD操作了。通过`SessionFactory`获取`Session`,然后使用`Session`的`save()`, `update()`, `delete()`, `get...

Global site tag (gtag.js) - Google Analytics