• 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.

  • 相关阅读:
    关于display:flex
    关于兼容性——百分比对于IE浏览器的影响
    谈谈一个菜鸟写了一段时间的静态页面
    2016.01.02
    课时21:函数:lambda表达式
    课时20:内嵌函数和闭包
    课时19:函数:我的地盘听我的
    课时18:函数:灵活即强大
    课时17:函数:Python的乐高积木
    课时16:序列
  • 原文地址:https://www.cnblogs.com/danghuijian/p/4400841.html
Copyright © 2020-2023  润新知