`

Hibernate事务与并发问题处理

阅读更多
数据库事务,是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。下文将讲解一些并发问题的处理。

一、数据库事务的定义

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。

1. 原子性(atomic),事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行

2. 一致性(consistent),事务在完成时,必须使所有的数据都保持一致状态。

3. 隔离性(insulation),由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。

4. 持久性(Duration),事务完成之后,它对于系统的影响是永久性的。

二、数据库事务并发可能带来的问题

如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。由于并发操作带来的数据不一致性包括:丢失数据修改、读”脏”数据(脏读)、不可重复读、产生幽灵数据:

假设数据库中有如下一张表:


1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。


在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了 id="402881e535194b8f0135194b91310001"的数据,T4时刻事务2取出了同一条数据,T5时刻事务1将age字段值更新为30,T6时刻事务2更新age为35并提交了数据,但是T7事务1回滚了事务age最后的值依然为20,事务2的更新丢失了,这种情况就叫做"第一类丢失更新(lost update)"。

2. 脏读(dirty read):如果第二个事务查询到第一个事务还未提交的更新数据,形成脏读。

在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了id="402881e535194b8f0135194b91310001"的数据,在T5时刻事务1将age的值更新为30,但是事务还未提交,T6时刻事务2读取同一条记录,获得age的值为30,但是事务1还未提交,若在T7时刻事务1回滚了事务2的数据就是错误的数据(脏数据),这种情况叫做" 脏读(dirty read)"。

3. 虚读(phantom read):一个事务执行两次查询,第二次结果集包含第一次中没有或者某些行已被删除,造成两次结果不一致,只是另一个事务在这两次查询中间插入或者删除了数据造成的。

在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1从数据库中查询所有记录,记录总共有一条,T4时刻事务2向数据库中插入一条记录,T6时刻事务2提交事务。T7事务1再次查询数据数据时,记录变成两条了。这种情况是"虚读(phantom read)"。

4. 不可重复读(unrepeated read):一个事务两次读取同一行数据,结果得到不同状态结果,如中间正好另一个事务更新了该数据,两次结果相异,不可信任。

在T1时刻开启了事务1,T2时刻开启了事务2,在T3时刻事务1从数据库中取出了 id="402881e535194b8f0135194b91310001"的数据,此时age=20,T4时刻事务2查询同一条数据,T5事务2更新数据age=30,T6时刻事务2提交事务,T7事务1查询同一条数据,发现数据与第一次不一致。这种情况就是"不可重复读(unrepeated read)"。

5. 第二类丢失更新(second lost updates):是不可重复读的特殊情况,如果两个事务都读取同一行,然后两个都进行写操作,并提交,第一个事务所做的改变就会丢失。

在T1时刻开启了事务1,T2时刻开启了事务2,T3时刻事务1更新数据age=25,T5时刻事务2更新数据age=30,T6时刻提交事务,T7时刻事务2提交事务,把事务1的更新覆盖了。这种情况就是"第二类丢失更新(second lost updates)"。

三、数据库事务隔离级别

为了解决数据库事务并发运行时的各种问题数据库系统提供四种事务隔离级别:

1. Serializable 串行化

2. Repeatable Read 可重复读

3. Read Commited 可读已提交

4. Read Uncommited 可读未提交

隔离级别与并发性能的关系:


每一个隔离级别可以解决的问题:


四、使用Hibernate设置数据库隔离级别

在Hibernate的配置文件中可以显示的配置数据库事务隔离级别。每一个隔离级别用一个整数表示:

8 - Serializable 串行化

4 - Repeatable Read 可重复读

2 - Read Commited 可读已提交

1 - Read Uncommited 可读未提交

在hibernate.cfg.xml中使用hibernate.connection.isolation参数配置数据库事务隔离级别。

五、使用悲观锁解决事务并发问题

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。

一个典型的依赖数据库的悲观锁调用:select * from account where name=”Erica” for update这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。悲观锁,也是基于数据库的锁机制实现。

在Hibernate使用悲观锁十分容易,但实际应用中悲观锁是很少被使用的,因为它大大限制了并发性:

图为Hibernate3.6的帮助文档Session文档的get方法截图,可以看到get方法第三个参数"lockMode" 或"lockOptions",注意在Hibernate3.6以上的版本中"LockMode"已经不建议使用。方法的第三个参数就是用来设置悲观锁的,使用第三个参数之后,我们每次发送的SQL语句都会加上"for update"用于告诉数据库锁定相关数据。

LockMode参数选择该选项,就会开启悲观锁。

T1,T2时刻取款事务和转账事务分别开启,T3事务查询ACCOUNTS表的数据并用悲观锁锁定,T4转账事务也要查询同一条数据,数据库发现该记录已经被前一个事务使用悲观锁锁定了,然后让转账事务等待直到取款事务提交。T6时刻取款事务提交,T7时刻转账事务获取数据。

六、使用乐观锁解决事务并发问题

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。

乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

Hibernate为乐观锁提供了3中实现:

1. 基于version

2. 基于timestamp

3. 为遗留项目添加添加乐观锁

配置基于version的乐观锁:

    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
     
    <hibernate-mapping> 
        <class name="com.suxiaolei.hibernate.pojos.People" table="people"> 
            <id name="id" type="string"> 
                <column name="id"></column> 
                <generator class="uuid"></generator> 
            </id> 
              
            <!-- version标签用于指定表示版本号的字段信息 --> 
            <version name="version" column="version" type="integer"></version> 
     
            <property name="name" column="name" type="string"></property> 
              
        </class> 
    </hibernate-mapping> 

配置基于timestamp的乐观锁:
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
     
    <hibernate-mapping> 
        <class name="com.suxiaolei.hibernate.pojos.People" table="people"> 
            <id name="id" type="string"> 
                <column name="id"></column> 
                <generator class="uuid"></generator> 
            </id> 
              
            <!-- timestamp标签用于指定表示版本号的字段信息 --> 
            <timestamp name="updateDate" column="updateDate"></timestamp> 
     
            <property name="name" column="name" type="string"></property> 
              
        </class> 
    </hibernate-mapping> 

遗留项目,由于各种原因无法为原有的数据库添加"version"或"timestamp"字段,这时不可以使用上面两种方式配置乐观锁,Hibernate为这种情况提供了一个"optimisitic-lock"属性,它位于<class>标签上:
    <?xml version="1.0" encoding="utf-8"?> 
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
     
    <hibernate-mapping> 
        <class name="com.suxiaolei.hibernate.pojos.People" table="people" optimistic-lock="all"> 
            <id name="id" type="string"> 
                <column name="id"></column> 
                <generator class="uuid"></generator> 
            </id> 
     
            <property name="name" column="name" type="string"></property> 
        </class> 
    </hibernate-mapping> 


将该属性的值设置为all,让该记录所有的字段都为版本控制信息。

原文链接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/27/2330008.html#C2
  • 大小: 4.6 KB
  • 大小: 11.5 KB
  • 大小: 9.6 KB
  • 大小: 10.1 KB
  • 大小: 10.8 KB
  • 大小: 9.8 KB
  • 大小: 66.4 KB
  • 大小: 40.2 KB
  • 大小: 8.7 KB
  • 大小: 6.8 KB
  • 大小: 77.6 KB
分享到:
评论

相关推荐

    Hibernate事务与并发问题处理[收集].pdf

    Hibernate事务与并发问题处理[收集].pdf

    Hibernate 事务和并发控制

    本文将深入探讨Hibernate中的事务和并发控制,这对于开发高效、稳定的数据库应用至关重要。 首先,我们来理解Hibernate中的事务管理。在数据库操作中,事务是保证数据一致性的重要手段。一个事务包含了一组数据库...

    Hibernate事务和并发控制

    事务和并发控制是数据库管理中的核心概念,特别是在使用ORM框架如Hibernate时,理解它们的工作原理至关重要。本文将深入探讨Hibernate中的事务管理和并发控制。 首先,事务是数据库操作的基本单位,它保证了数据的...

    hibernate事务,并发及缓存管理实例

    一、Hibernate事务管理 在数据库操作中,事务确保了数据的一致性和完整性。Hibernate提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ)和串行化...

    hibernate 对事务并发处理

    Hibernate 对事务并发处理 在 Hibernate 中,对事务并发处理是非常重要的, especialmente 在多用户环境中。事务处理的目的是为了保证数据的可靠性和一致性。 事务四个特性 ACID 1. 原子性(Atomicity):事务...

    详解Hibernate事务处理机制

    ### 详解Hibernate事务处理机制 #### 一、引言 Hibernate作为一款优秀的对象关系映射(ORM)框架,在Java开发领域扮演着极其重要的角色。它不仅简化了数据持久化的复杂性,还提供了一系列强大的功能来支持高效的...

    Spring Hibernate 事务处理 详细说明

    3. **Hibernate事务配置:**在Spring中,需要配置Hibernate SessionFactory,并将其注入到需要进行数据库操作的服务中。同时,通过`PlatformTransactionManager`接口(如HibernateTransactionManager)配置事务管理...

    Hibernate教程26_事务并发处理

    本教程主要聚焦于Hibernate中的事务并发处理,包括悲观锁和乐观锁两种策略,这对于我们理解如何在高并发环境中确保数据的一致性和完整性至关重要。 首先,事务是数据库操作的基本单元,它确保一组操作要么全部成功...

    Hibernate4实战 之第五部分:Hibernate的事务和并发

    #### 三、事务并发处理 Hibernate 提供了两种主要的并发控制机制: 1. **乐观锁(Optimistic Locking)**:假设数据不会经常冲突,只有在提交时才会进行冲突检测。Hibernate 通过版本字段实现自动乐观并发控制。 2....

    hibernate的事务核并发

    ### Hibernate事务管理 #### 非托管环境下的事务处理 在非托管环境中,如独立的Java应用程序或Web应用中,Hibernate通过其内部的连接池机制管理数据库连接。为了执行事务操作,开发者需要遵循以下步骤: 1. **...

    Hibernate part 14:查询及数据库并发事务

    9. **实体状态与生命周期**:理解Hibernate中的临时态、持久态、瞬时态和脱管态对于正确处理并发事务至关重要。 10. **最佳实践**:包括合理设计实体关系、避免N+1查询、使用批处理等,都是提升并发性能的关键。 ...

    Hibernate事务(源码)

    **Hibernate事务管理详解** 在Java开发中,尤其是在企业级应用中,事务管理是不可或缺的一部分。Hibernate作为一款流行的ORM(对象关系映射)框架,提供了强大的事务处理能力。本篇文章将深入探讨Hibernate中的事务...

    hibernate事务管理机制.doc

    【hibernate事务管理机制】是指在使用Hibernate框架进行数据库操作时,如何管理和协调事务的一系列规则和策略。事务管理是确保数据一致性、完整性和并发控制的重要机制。 **悲观锁**是预防性的锁定策略,它假设并发...

    Hibernate中,利用版本管理机制来控制事务并发

    在Java的持久化框架Hibernate中,版本管理机制是实现事务并发控制的重要手段。它通过维护对象的版本信息,确保在多线程环境下数据的一致性和完整性。本文将深入探讨Hibernate中的版本管理机制及其在控制事务并发中的...

    hibernate的事务和并发资料.pdf

    Hibernate作为一款流行的ORM框架,它简化了与数据库的交互,但同时也需要开发者理解其背后的事务处理机制。 首先,Hibernate支持两种类型的事务管理:JDBC连接管理和JTA(Java Transaction API)资源管理。它并未...

    课程hibernate的事务和并发.pdf

    《课程hibernate的事务和并发》主要探讨了在Hibernate框架中如何管理和处理事务以及并发控制。Hibernate作为一款流行的Java ORM(对象关系映射)工具,其事务处理和并发控制策略对于开发高效、稳定的数据库应用至关...

    day36 09-Hibernate中的事务:事务处理

    **一、Hibernate事务的概念** 事务是一组数据库操作,这些操作被视为一个逻辑单元,要么全部执行,要么全部不执行。这是为了保证数据的一致性。在Hibernate中,事务管理通常通过SessionFactory和Session接口来实现。...

    Hibernate事务处理

    ### Hibernate事务处理详解 #### 一、事务处理概念与特性 事务处理是数据库操作中一个核心的概念,尤其在处理复杂的业务逻辑时,确保数据的一致性和完整性至关重要。Hibernate作为Java领域中广泛使用的对象关系...

Global site tag (gtag.js) - Google Analytics