当前位置:编程学习 > JAVA >>

hibernate的优化-事务处理 .

1.事务概述

事务就是指作为单个逻辑工作单元执行的一组数据操作,这些操作要么必须全部成功,要么必须全部失败,以保证数据的一致性和完整性。事务具有ACID属性:

原子性:自然界最小的,事务的内容要么都做要么都不做

一致性: 事务结束后状态一致;系统状态和业务的逻辑规则一致

隔离性: 就是加锁机制,多个事务访问同一个数据分别被隔开

持久性: 一旦事务结束,事务的结果被永久的保存下来

数据库事务管理

    数据库事务的ACID特性是由关系数据库管理系统(RDBMS)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。

   数据库管理系统采用锁机制来实现事务的隔离性。

2.Hibernate应用程序中的事务管理

Hibernate对JDBC进行轻量级的对象封装,Hibernate本身在设计时并不具备事务处理功能,平时所用的Hibernate的事务,只是将底层的JDBCTransaction或者JTATransaction进行一下封装,在外面套上Transaction和Session的外壳,其实底层都是通过委托底层的JDBC或JTA来实现事务的调度功能。

1)Hibernate中使用JDBC事务

要在Hibernate中使用JDBC事务,可以在hibernate.cfg.xml中指定Hibernate事务为JDBCTransaction。注意:如果不配置,默认使用JDBC事务。

<property name=“hibernate.transaction.factory_class”>

         org.hibernate.transaction.JDBCTransactionFactory

 </property>

Transaction tx=null;

try{

       tx=session.beginTransaction();

       //执行持久化操作

       tx.commit();

}catch(Exception e){

           if(tx!=null)  tx.rollback();

          throw e;

} finally{

        session.close();

}

2) Hibernate中使用JTA事务

JTA(Java Transaction API) 可以简单的理解成跨数据库的事务,由应用JTA 容器实现。使用JTATransaction需要配置hibernate.transaction.factory_class参数,该参数缺省值是org.hibernate.transaction. JDBCTransactionFactory,当使用JTATransaction时需要将该参数改成org.hibernate.transaction.JTATransactionFactory,并配置jta.UserTransaction参数JNDI名(Hibernate在启动JTATransaction时要用该值到JNDI的上下文Context中去找javax.transaction.UserTransaction)。

javax.transaction.UserTransactin tx = context.lookup(“jndiName”);

try{

   tx.begin();

   //多个数据库的session操作;

   //session1….

   //session2….

   tx.commit();

}catch(Exception e){

   tx.rollback(); throw e;

}

3. 并发访问控制

数据库事务并发引起的问题:

丢失更新:你改的时候我也改,我改的内容覆盖你修改的或者改的内容回滚了,没有保存进去。

脏读:读到脏数据,你读取之后我才修改的,你读取的内容无效或者也是回滚,我修改的一半你就读取了最后我给回滚了。

不可重复读:两次查询的内容不一样;第二次读取的时候被修改

幻读:两次查询的内容不一样;在第二次查询的时候发现了与第一次不一样的内容;可能原因是中间有人进行更改或者删除。
事务隔离级别:为了解决多个事务并发引发的问题,让用户根据需要在事务的隔离性和并发性之间做合理的权衡。数据库系统提供了4种事务隔离级别。
读未提交(Read Uncommitted):隔离级别最低

读已提交(Read committed):一般情况下用这个

可重复读(Repeatable Read)

串行化(Serializable):隔离级别最高,所以并发问题都没有了

数据库系统采用不同的锁类型来实现这4中隔离级别。具体实现过程对用户是透明的,用户只要选择合适的隔离级别就可以了。

隔离级别越高,越能保证数据的完整性和一致性,但对并发性能的影响也越大。对于大多数应用程序,可以优先考虑隔离级别为Read Committed,它能够避免藏读,而且具有较好的并发性能。

Hibernate的配置文件可以显示的设置隔离级别。每种隔离级别对于一个正整数。

Read Uncommitted:1

Read Committed: 2

Repeatable  Read: 4

Serializable:8

<property name=“hibernate.connection.isolation”>2</property>

4. 乐观并发控制

当数据库系统采用Read Committed隔离级别时,仍不能防止不可重复读和幻读。在可能出现这种问题的场合,可以在应用程序中采用乐观锁和悲观锁方式来解决。

乐观锁是假定当前事务操作数据库资源时,不会有其他事务同时访问,因此不做数据库层次上的锁定。为了维护正确数据,hibernate用version和timestamp来实现。

1)使用版本号进行版本控制

  在持久化类中定义一个version属性。类型只能是整型的。

在映射文件中添加<version>标签,注意一定要放在<id>元素后面。

5.悲观并发控制

悲观锁是假定当前事务操作数据资源时,一定有其他事务同时访问该数据资源,所以先锁定资源。

一般实现方式是由数据库来实现,采用独占锁来锁定资源。使用get(),load(),是可以显示指定锁定模式:LockMode.UPGRADE

Session.get(Student.class,1,LockMode.UPGRADE);

6. 配置C3p0连接池

   <!-- 启用c3p0连接池  设置连接池提供的供应商 -->

   <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

   <!-- 最大连接数 -->

   <property name="c3p0.max_size">20</property>

   <!-- 最小连接数 -->

   <property name="c3p0.min_size">5</property>

   <!-- 每次请求连接的数目 -->

   <property name="c3p0.acquire_increment">5</property>

   <!-- 设置过期时间,以秒为单位,如果连接池中 -处于空闲状态的连接超过了这个时间,该连接就会从连接池中删除-->

   <property name="c3p0.timeout">120</property>

   <!-- 每个3000秒检查连接池中的空闲连接  -->

   <property name="c3p0.idle_test_period">3000</property>

7. Hibernate不适合的场景

不适合OLAP(On-Line Analytical Processing联机分析处理),以查询分析数据为主的系统;适合OLTP(on-line transaction processing联机事务处理)。

对于些关系模型设计不合理的老系统,也不能发挥hibernate优势。数据量巨大,性能要求苛刻的系统,hibernate也很难达到要求, 批量操作数据的效率也不高。

1).Hibernate 整合Struts

 Hibernate框架主要使用在持久层中,完成实体类的CRUD操作。

2). 泛型DAO模式Hibenate实现

3).OpenSessionInView模式

8.  案例分析

Hibernate.cfg.xml中要配置如下数据:

<property name="hibernate.connection.isolation">2</property>

映射文件中配置:

<version name="version"></version>

 

 

@Test

   //测试乐观锁;添加数据,版本号自动生成不用手动添加

   publicvoid testAdd(){

      Session session = HibernateUtil.getSession();

      session.beginTransaction();

     

      User u = new User();

      u.setName("李四");

      u.setBirthday(new Date());

     

      session.save(u);

     

      session.getTransaction().commit();

      HibernateUtil.close();

   }

   @Test

   //测试乐观锁;更改数据,版本号会自动加1

   publicvoid testupdate(){

      Session session = HibernateUtil.getSession();

      session.beginTransaction();

     

      User user = (User) session.load(User.class,4);

     

      user.setName("王五");

  &n

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,