作者:狂放不羁
网址: http://yuquan-nana.javaeye.com

>>> 转载请注明出处!<<<
 
前篇文章总结了最基础的事务的概念。现在就总结一下具体事务在JavaEE持久层的应用。具体分为两部分,第一部分是事务在Hibernate 中的应用,第二部分是在JPA中的应用。下面先总结一下,事务在Hiernate里的应用。
 
首先需要声明的是,hibernate本身没有事务功能。它只是借助JDBC事务,或者JTA事务来实现事务的管理,它只是封装了事务的使用方法。一般事务控制定界到service层,但是为了方便,以下的代码将事务代码放在Dao层。事务在Hiibernate中的应用具体可以分为一下三部分:
 
1 JDBC事务在Hibernate的应用。如果我们系统不需要分布式的话,那么就可以采用JDBC事务来提供事务服务。要想在Hibernate里使用JDBC事务,我们必须要配置如下属性:hibernate.transaction.factory_class=org.hiberante.transaction.JDBCTransactionFactory.
在此种情况下典型的编码方式如下:
Java代码
public class XXXDao ...{        
                
        Session session ;        
        Transaction tx ;        
    
         public void crudOperation(){        
                
         try{        
                
                session = HibernateUtil.getCurrentSession();        
                tx = session.beginTransaction();        
                 //完成具体的CRUD操作。        
                tx.commit();        
                
        } catch(RuntimeException e){        
                
                tx.rollback();        
        } finally{        
                
                 this.getSession().close();        
        }        
                        
        }        
}    
 
在此种情况下,Hibernate的数据库连接可以由容器来管理,也可以自己管理一个数据库连接池,并且只有当事务开始的时候才获得connection.需要注意的是,tx.beginTransaction(),此语句实际上是将获得connection的自动提交模式关闭,也就是connection.setAutoCommit(false)。
 
2 JTA事务在Hibernate中的应用。如果要想使用JTA事务提供的分布式事务服务,那么必须要做以下事情:
 首先,需要确保相对应的JDBC驱动程序支持XAResource接口,因为只有支持此接口的JDBC Driver才能纳入JTA事务管理器的管理。
 其次,需要更改配置如下:
hibernate.transaction.factory_class=org.hiberante.transaction.JTATransactionFactory.
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup.(此配置根据自己的JavaEE AS来配置).
确保以上两个条件后,就需要考虑选择JTA provider了,是选择JavaEE服务器来提供JTA服务呢,还是通过开源的JTA组件来提供服务。如果采用开源的组件的话,可以采用如JBoss的JTA组件等。如果采用JavaEE服务器的话,则可以直接受益与Application server提供的JTA服务了。
需要注意的是在这种情况下,hibernate不再管理数据库连接池了,它需要通过JNDI来获取JTA提供者暴漏的连接池服务。
在此种模式下,编程模型可以采用如下两种:
1)利用hibernate的Transaction接口。典型的代码如下:
Java代码
public class XXXDao ...{        
                
        Session session ;        
        Transaction tx ;        
    
         public void crudOperation(){        
                
         try{        
                
                session = HibernateUtil.getCurrentSession();        
                tx = session.beginTransaction();        
                 //完成具体的CRUD操作。        
                tx.commit();        
                
        } catch(RuntimeException e){        
                
                tx.rollback();        
        } finally{        
                
                 this.getSession().close();        
        }        
                        
        }        
}    
 
如果采用Hibernate的原生接口的话,那么不需要应用程序flush session和关闭session了,因为在模型下,hibernate内部会在事务提交的时候自动flush和close session.但是这样做不好的地方就是将应用程序绑定到hiberante原生(Native)接口,不便于系统的移植,所以为了方便系统移植,以及将事务服务的提供留给应用程序部署者来完成,我们可以采用standard JTA接口。JTA编程接口典型的代码如下:
Java代码
public class XXXDao ...{        
                
        Session session ;        
        UserTransaction utx = (UserTransaction)ServiceLocator.getUserTransaction( "JNDIName") ;        
    
         public void crudOperation(){        
                
         try{        
                
            utx.begin():        
                session = HibernateUtil.getCurrentSession();        
                        
                 //完成具体的CRUD操作。        
                utx.commit();        
                session.flush(); //此时需要程序来flush session        
                
        } catch(RuntimeException e){        
                
                utx.rollback();        
                 //日志记录等        
        } finally{        
                
                 this.getSession().close();        
        }        
                        
        }        
}    
 
 此时值得注意的时,需要应用程序来刷新session,如果想要激活自动刷新和自动关闭session的功能,需要配置如下两个属性:
* hibernate.transaction.flush_before_completion和hibernate.transaction.auto_close_session为true.这样以来当JTA事务提交和回滚的时候Hibernate就会自动刷新和关闭session.
 
如果觉得以上代码不够美观的话,那是正常的,因为代码中充斥着try,catch语句,以及将事务处理的代码侵入到了业务代码中。如何避免这些烦人的try ,catch语句,以及事务处理代码,就需要比较流行的AOP来解决。如果采用AOP的话,建议采用现成的AOP框架来实现,比如spring就支持hibernate的声明式事务管理,当然也可以采用代理等模式来自己实现,看系统需要和个人爱好。
 
3.采用容器管理事务(CMT).如果采用JavaEE AS的话,我们就可以直接使用EJB容器提供的声明式事务管理功能了。在此种模式下,其实底层事务还是JTA,不过事务控制是由容器来控制,应用程序只需要负责业务核心就OK了。如果采用CMT的话,可以通过session bean来封装 hibernate session,这样可以通过EJB的Annotation来注解业务方法,这样以来就不需要我们关心事务代码了,只需要配置支持XA 标准的数据源就好了。不过此时的事务工厂类要配置为CMTTransactionFactory.
 
未完待续........