hibernate 和 jpa

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

>>>转载请注明出处!<<<

事务在企业应用系统开发中占据着非常重要的作用,它可以确保一组对资源操作的原子性,并且事务具有ACID属性。先说说两种最常见的事务模型,它们 是平面(Flat)事务和嵌入式(Nested)事务。平面事务是由一系列的原子性的操作构成,这些操作一起组成了单个工作单元。而嵌入式事务容许将原子 性的工作单元嵌入到其它的工作单元中,并且对于嵌入式事务来说,嵌入的子事务即使回滚了,也不会引起外层事务的回滚。但是当前的EJB规范没有对嵌入式事 务做出具体的要求,因此EJB的事务管理器只支持平面事务。下面就具体总结一下J2EE中的两种平面事务:

1 JDBC事务。JDBC事务相对来说,比较容易理解。既然是JDBC,那么它的底层事务是通过数据库的事务来实现的。

2 分布式JTA事务。JTA事务对分布式的应用系统提供了事务功能。它的底层通过JTS提供的接口来实现。对于我们应用开发者来说,只需要熟悉JTA接口就 OK了。JTA provider可以作为一个独立的组件存在,也可以嵌入到具体的J2EE 应用服务器。对于JTA事务,需要理解一下几个概念:

1)事务管理器。事务管理器负责协调具体的资源管理器来完成事务控制。

2)资源管理器。资源管理器具体来说就是各种驱动程序,对于数据库来说,就是具体的JDBC驱动程序。

3)事务性的资源。数据库,JMS队列,遗留系统等。

4)两阶段提交协议(2PC)。2PC对于JTA事务来说相当的重要。2PC的实现非常复杂,简单点来说就是:第一个阶段准备事务的提交,第二个阶段:如果第一个阶段所有的资源管理器都容许提交,那么就提交事务,如果有一个资源管理不同意提交的化,则回滚事务。

理解了以上的几个概念后,还需要了解一下几个接口,这几个接口在JTA中也是非常重要的。总结如下:

1)javax.transaction.xa.XAResource.JTA provider通过此接口与支持X/OPEN 标准的资源管理器通信。(比如支持XA接口的JDBC驱动程序)

2)javax.transaction.TransactionManager.JTA provider通过此接口实现与J2EE application server的通信。

3)javax.transaction.UserTransaction。此接口对于我们应用开发者来说最重要。它提供了begin(),commit(),rollback()等操作事务的方法。

以上是事务的一些基础的概念,等理解了它们以后,就可以开始事务在J2EE具体应用之旅了。

前篇文章总结了最基础的事务的概念。现在就总结一下具体事务在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代码 复制代码
  1. public class XXXDao ...{  
  2.       
  3.      Session session ;  
  4.      Transaction tx ;  
  5.   
  6.     public void crudOperation(){  
  7.       
  8.     try{  
  9.       
  10.          session = HibernateUtil.getCurrentSession();  
  11.          tx = session.beginTransaction();  
  12.         //完成具体的CRUD操作。  
  13.          tx.commit();  
  14.       
  15.      }catch(RuntimeException e){  
  16.       
  17.          tx.rollback();  
  18.      }finally{  
  19.       
  20.         this.getSession().close();  
  21.      }  
  22.           
  23.      }  
  24. }  
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代码 复制代码
  1. public class XXXDao ...{  
  2.       
  3.      Session session ;  
  4.      Transaction tx ;  
  5.   
  6.     public void crudOperation(){  
  7.       
  8.     try{  
  9.       
  10.          session = HibernateUtil.getCurrentSession();  
  11.          tx = session.beginTransaction();  
  12.         //完成具体的CRUD操作。  
  13.          tx.commit();  
  14.       
  15.      }catch(RuntimeException e){  
  16.       
  17.          tx.rollback();  
  18.      }finally{  
  19.       
  20.         this.getSession().close();  
  21.      }  
  22.           
  23.      }  
  24. }  
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代码 复制代码
  1. public class XXXDao ...{  
  2.       
  3.      Session session ;  
  4.      UserTransaction utx = (UserTransaction)ServiceLocator.getUserTransaction("JNDIName") ;  
  5.   
  6.     public void crudOperation(){  
  7.       
  8.     try{  
  9.       
  10.        utx.begin():  
  11.          session = HibernateUtil.getCurrentSession();  
  12.           
  13.         //完成具体的CRUD操作。  
  14.          utx.commit();  
  15.          session.flush();//此时需要程序来flush session  
  16.       
  17.      }catch(RuntimeException e){  
  18.       
  19.          utx.rollback();  
  20.         //日志记录等  
  21.      }finally{  
  22.       
  23.         this.getSession().close();  
  24.      }  
  25.           
  26.      }  
  27. }  
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.

原文地址:https://www.cnblogs.com/danghuijian/p/4400841.html