Hibernate悲观锁与乐观锁

本文深入探讨了Hibernate框架中乐观锁与悲观锁的工作机制,包括它们在多线程环境下如何处理数据一致性问题。文章通过实例演示了如何在Hibernate中启用这两种锁模式,以及如何在出现并发冲突时进行相应的错误处理。重点强调了乐观锁通过版本号机制确保数据一致性的优势,以及悲观锁在资源锁定方面的传统方法。

在使用Hibernate 的乐观锁时,如果是在多线程同时访问到同一数据并且先后修改同一数据,采用乐观锁的版本更新机制来处理...
因为使用session.commit()提交数据时会清理缓存,如果发现缓存里面存有数据而会执行update语句进行id与version匹配,但是version的值现在已经改变,无法修改数据库的数据,所以就会报出org.hibernate.StaleObjectStateException异常。
这个时候异常怎么进行捕获..
 



悲观锁Hibernate悲观锁与乐观锁

       在多个客户端可能读取同一笔数据或同时更新一笔数据的情况下,必须要有访问控制的手段,防止同一个数据被修改而造成混乱,最简单的手段就是对数据进行锁定。在自己进行数据读取或更新等动作时,锁定其他客户端不能对同一笔数据进行任何的动作。

       悲观锁(Pessimistic Locking),如其名称所示,悲观地认定每次资料存取时,其他的客户端也会存取同一笔数据,因此将会锁住该笔数据,直到自己操作完成后再解除锁。

       悲观锁假定任何时刻存取数据时,都可能有另一个客户也正在存取同一笔数据,因而对数据采取了数据库层次的锁定状态,在锁定的时间内其他的客户不能对数据进行存取。对于单机或小系统而言,这并不成问题,然而如果是在网络上的系统,同时间会有许多访问的机器,如果每一次读取数据都造成锁定,其后继的存取就必须等待,这将造成效能上的问题,造成后继使用者的长时间等待。

       悲观锁通常透过系统或数据库本身的功能来实现,依赖系统或数据库本身提供的锁机制。Hibernate即是如此,可以利用Query或Criteria的setLockMode()方法来设定要锁定的表或列及其锁模式,可设定的锁模式有以下几个。

       LockMode.UPGRADE:利用数据库的for update子句进行锁定。

       LockMode.UPGRADE_NOWAIT:使用for update nowait子句进行锁定,在Oracle数据库中使用。

       下面来实现一个简单的例子,测试一下采用悲观锁时数据库是如何进行操作的。

             Query query = session.createQuery("from User user");

              query.setLockMode("user", LockMode.UPGRADE);

该方法在执行查询之前通过Query对象的setLockMode()方法设置了访问User对象的模式, 除了Query对象外,也可以在使用Session的load()或是lock()时指定锁模式

乐观锁Hibernate悲观锁与乐观锁

       乐观锁(Optimistic Locking)认为资料的存取很少发生同时存取的问题,因而不做数据库层次上的锁定。为了维护正确的数据,乐观锁是使用应用程序上的逻辑来实现版本控制的。

在使用乐观锁策略的情况下,数据不一致的情况一旦发生,有几个解决方法,一种是先更新为主,一种是后更新为主,比较复杂的就是检查发生变动的数据来实现,或是检查所有属性来实现乐观锁。

       Hibernate中通过检查版本号来判断数据是否已经被其他人所改动,这也是Hibernate所推荐的方式。在数据库中加入一个version字段记录,在读取数据时连同版本号一同读取,并在更新数据时比较版本号与数据库中的版本号,如果等于数据库中的版本号则予以更新,并递增版本号,如果小于数据库中的版本号就抛出异常。

       下面就来在前面例子的基础上进行Hibernate乐观锁的测试。

       首先需要修改前面所实现的业务对象,在其中增加一个version属性,用来记录该对象所包含数据的版本信息,修改后的User对象下面代码所示:

       修改后的User对象

package com.xuyesheng.hibernate.lock;

public class User {

       private String id;

       private Integer version; // 增加版本属性

       private String name;

       private Integer age;

       // 省略了getter和setter方法

       ……

}

       然后是修改映射文件,增加version属性的配置。在这里需要注意的是,这里的version属性应该使用专门的<version>元素来进行配置,这样才能使其发挥乐观锁的作用。如果还使用<property>元素来进行配置,那么Hibernate只会将其作为一个普通的属性来进行处理。

修改后的映射文件

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

       "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

       "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.hxex.hibernate.lock">

       <class name="User" table="USERINFO" optimistic-lock="version">

              <id name="id" column="userId"><generator class="uuid.hex"/></id>

              <version name="version" column="version" type="java.lang.Integer"/>

              <property name="name" column="name" type="java.lang.String"/>

              <property name="age" column="age" type="java.lang.Integer"/>

       </class>

</hibernate-mapping>

每次对TUser进行更新的时候,我们可以发现,数据库中的version都在递增。而如果我们尝试在tx.commit 之前,启动另外一个Session,对名为Erica 的用户进行操作,以模拟并发更新时的情形:
代码内容

1 Hibernate悲观锁与乐观锁Session session= getSession();  
2
Hibernate悲观锁与乐观锁Criteria criteria= session.createCriteria(TUser. class );  
3
Hibernate悲观锁与乐观锁criteria.add(expression_r_r.eq(" name ", " Erica" ));  
4
Hibernate悲观锁与乐观锁Session session2= getSession();  
5
Hibernate悲观锁与乐观锁Criteria criteria2= session2.createCriteria(TUser. class );  
6
Hibernate悲观锁与乐观锁criteria2.add(expression_r_r.eq(" name ", " Erica" ));  
7
Hibernate悲观锁与乐观锁List userList= criteria.list();  
8
Hibernate悲观锁与乐观锁List userList2= criteria2.list();TUser user = (TUser)userList.get(0 );  
9
Hibernate悲观锁与乐观锁TUser user2= (TUser)userList2.get( 0 );  
10
Hibernate悲观锁与乐观锁Transaction tx= session.beginTransaction();  
11
Hibernate悲观锁与乐观锁Transaction tx2= session2.beginTransaction();  
12
Hibernate悲观锁与乐观锁user2.setUserType(99 );  
13
Hibernate悲观锁与乐观锁tx2.commit();  
14Hibernate悲观锁与乐观锁user.setUserType(1 );  
15
Hibernate悲观锁与乐观锁tx.commit();  
16Hibernate悲观锁与乐观锁
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值