--Hibernate的乐观锁与悲观锁
锁( locking )
业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算处理中,我们希望针对某个 cut-off 时间点的数据进行处理,而不希望在结算进行过程中(可能是几秒种,也可能是几个小时),数据再发生变化。此时,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的 “锁” ,即给我们选定的目标数据上锁,使其无法被其他程序修改。Hibernate 支持两种锁机制:即通常所说的 “悲观锁( Pessimistic Locking )”和 “乐观锁( Optimistic Locking )” 。
悲观锁( Pessimistic Locking )
悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
一个典型的倚赖数据库的悲观锁调用:
select * from account where for update
这条 sql 语句锁定了 account 表中所有符合检索条件(name=”Erica”)的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。Hibernate 的悲观锁,也是基于数据库的锁机制实现
乐观锁( Optimistic Locking )
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几百上千个并发,这样的情况将导致怎样的后果。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。
读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
乐观锁机制避免了长事务中的数据库加锁开销(操作员 A 和操作员 B 操作过程中,都没有对数据库数据加锁),大大提升了大并发量下的系统整体性能表现。需要注意的是,乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户余额更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。在系统设计阶段,我们应该充分考虑到这些情况出现的可能性,并进行相应调整(如将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途径,而不是将数据库表直接对外公开)。
Hibernate 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数据库的更新操作,利用 Hibernate 提供的透明化乐观锁实现,将大大提升我们的生产力。
Hibernate 中可以通过 class 描述符的 optimistic-lock 属性结合 version描述符指定。
现在,我们为之前示例中的 TUser 加上乐观锁机制。
1 . 首先为 TUser 的 class 描述符添加 optimistic-lock 属性:
<hibernate-mapping>
<class table="t_user" dynamic-update="true"
dynamic-insert="true" optimistic-lock="version">
……
</class>
</hibernate-mapping>
optimistic-lock 属性有如下可选取值:
none:无乐观锁
version:通过版本机制实现乐观锁
dirty:通过检查发生变动过的属性实现乐观锁
all:通过检查所有属性实现乐观锁
其中通过 version 实现的乐观锁机制是 Hibernate 官方推荐的乐观锁实现,同时也是 Hibernate 中,目前唯一在数据对象脱离 Session 发生修改的情况下依然有效的锁机制。因此,一般情况下,我们都选择 version 方式作为 Hibernate 乐观锁实现机制。
2 . 添加一个 Version 属性描述符
<hibernate-mapping>
<class table="t_user" dynamic-update="true" dynamic-insert="true"
optimistic-lock="version">
<id column="id" type="java.lang.Integer">
<generator >
</generator>
</id>
<version column="version" name="version" type="java.lang.Integer"/>
……
</class>
</hibernate-mapping>
测试代码
public class TestLock {
static Session objSession;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
objSession = HibernateSessionFactory.getSession();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
objSession.close();
}
@Test
public void test_LDH_b() {
try {
objSession.beginTransaction();
User objUser = (User) objSession.load(User.class, 1,LockMode.UPGRADE);
System.out.println("用户名称:" + objUser.getName());
System.out.println("刘德华修改帐户信息当中。。。。。。。。。。。。。");
objUser.setName("LDH_HD");
objSession.save(objUser);
objSession.getTransaction().commit();
} catch (Exception e) {
System.out.println("错误信息" + e.getMessage());
objSession.getTransaction().rollback();
}
}
}
分享到:
相关推荐
测试Hibernate数据库ch03.sql
CH08Hibernate框架介绍.ppt
- Session:是Hibernate的主要工作单元,它提供了与数据库交互的接口,负责对象的创建、更新、删除和查询。 - Transaction:处理数据库的事务,确保数据的一致性。 - Query:提供SQL语句的面向对象表示,支持HQL...
在Hibernate中,实体是与数据库表对应的Java类,它们通过注解或XML配置来定义映射关系。Hibernate的Session接口是操作实体的主要入口,它负责管理实体的生命周期,包括加载、保存、更新和删除等操作。在Chapter5中,...
在Hibernate中,这个过程通过映射机制来实现,将Java对象与数据库表对应,使得对象的操作可以透明地转换为SQL语句。 二、Hibernate概览 Hibernate作为ORM框架,提供了一种规范,使得Java开发者可以通过编写少量的...
数据库ch03数据库ch03
在本资源中,“精通eclipse web开发ch03-ch06”显然是一份关于使用Eclipse进行Web应用程序开发的学习资料,涵盖了从第三章到第六章的内容。Eclipse是一款广泛使用的集成开发环境(IDE),尤其在Java开发领域备受青睐...
深入理解Hibernate的源码,不仅可以帮助开发者提高开发效率,还能提升对数据库管理与Java对象持久化的理解。本章我们将聚焦于Hibernate源码的第四个章节,主要探讨Java对象如何通过Hibernate实现持久化,以及其背后...
2. **配置与环境搭建**:介绍了如何配置 Hibernate,包括设置数据库连接、配置日志等。 3. **映射策略**:详细阐述了 Hibernate 中的多种映射策略,例如一对一、一对多、多对多等映射方式,并提供了相应的示例代码。...
Hibernate作为Java领域中最流行的ORM(对象关系映射)框架,能够简化数据库操作,将SQL语句与Java代码分离,提高开发效率。接下来,我们将深入探讨这些关系类型以及如何在实际项目中应用它们。 一、一对多关系(One...
14. **Hibernate与Spring整合** Spring的声明式事务管理与Hibernate结合,能简化事务处理。同时,Spring的AOP(面向切面编程)可用于实现日志、性能监控等功能。 15. **最佳实践与性能调优** 使用Hibernate时,要...
在Hibernate中,我们通过Hibernate的注解或XML配置文件,定义实体类与数据库表的映射关系。例如,@Entity表示该类为一个数据库表,@Id表示主键,@GeneratedValue指定主键生成策略。 四、持久化操作 1. Save()和...
### Hibernate多表联合查询详解 #### 一、引言 在实际项目开发中,我们经常需要处理复杂的数据库查询,特别是涉及到多个表之间的关联查询。Hibernate作为一款流行的Java持久层框架,提供了一种非常便捷的方式来处理...
Hibernate使得Java开发者能够轻松地将业务对象与数据库中的记录进行映射,从而极大地简化了数据操作。在“精通Hibernate源码Chapter 7”中,我们将详细讲解以下几个关键知识点: 1. **对象状态管理**:Hibernate...
3. Session与事务(Session & Transaction):Session是Hibernate的核心接口,它负责管理对象的状态,并提供与数据库交互的能力。事务管理是Session的重要职责,保证数据的完整性和一致性。 二、对象状态与转换 1....
标题中的"CH341SER_ANDROID.ZIP_340手机驱动_CH341SER_ANDROID_CH34xUARTDemo_ch34"表明这是一个与CH341系列USB转UART(通用异步收发传输器)驱动相关的压缩包,主要用于Android设备。其中"340手机驱动"指的是该驱动...
- `ch10`、`ch07`、`ch02`、`ch08`、`ch03`、`ch04`:这些文件夹很可能是按照章节划分的源码示例,每个章节可能对应Hibernate的不同主题或功能。例如: - `ch02`可能是关于实体类和持久化模型的介绍,包括注解或...
CH372DRV.rar 是一个包含了CH372D和CH372DRV相关驱动程序和API的压缩包,主要用于支持基于USB接口芯片CH375的设备在Windows操作系统上的正常运行。CH372和CH375是常见的USB接口控制器,常用于数据传输、读卡器以及...
CH375是一款由芯程科技(Silicon Chip Technology)开发的USB接口控制器,主要用于实现通用串行总线(Universal Serial Bus, USB)与微控制器之间的通信。在给定的压缩包“CH375WDM.rar”中,包含了一系列与CH375...