1、Pessimistic Locking 悲观锁:
它指的是对数据被外界修改持保守态度。假定任何时刻存取数据时,都可能有另一个客户也正在存取同一笔数据,为了保持数据被操作的一致性,于是对数据采取了数据库层次的锁定状态,依靠数据库提供的锁机制来实现。
基于jdbc实现的数据库加锁如下:
select * from account where name="mary" for update
在更新的过程中,数据库处于加锁状态,任何其他的针对本条数据的操作都将被延迟。本次事务提交后解锁。
Hibernate 的加锁模式(LockMode类指定)有:
LockMode.NONE |
如果缓存中存在对象,直接返回该对象的引用,否则通过select语句到数据库中加载该对象,默认值. |
LockMode.READ |
不管缓存中是否存在对象,总是通过select语句到数据库中加载该对象,如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的对象是否和数据库中对象版本一致 |
LockMode.UPGRADE |
不管缓存中是否存在对象,总是通过select语句到数据库中加载该对象,如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的对象是否和数据库中对象的版本一致,如果数据库系统支持悲观锁(如Oracle/MySQL),就执行select...forupdate语句,如果不支持(如Sybase),执行普通select语句 |
LockMode.UPGRADE_NOWAIT |
和LockMode.UPGRADE具有同样功能,此外,对于Oracle等支持updatenowait的数据库,执行select...for updatenowait语句,nowait表明如果执行该select语句的事务不能立即获得悲观锁,那么不会等待其它事务释放锁,而是立刻抛出锁定异常 |
LockMode.WRITE |
保存对象时会自动使用这种锁定模式,仅供Hibernate内部使用,应用程序中不应该使用它 |
LockMode.FORCE |
强制更新数据库中对象的版本属性,从而表明当前事务已经更新了这个对象 |
(此处加锁模式参考网友文章)http://blog.sina.com.cn/s/blog_6ac4c6cb010186cn.html
显式的用户指定"可以通过以下几种方式之一来表示:
•调用 Session.load() 的时候指定锁定模式(LockMode)。
•调用 Session.lock()。
•调用 Query.setLockMode()。
如果在 UPGRADE 或者 UPGRADE_NOWAIT 锁定模式下调用 Session.load(),并且要读取的对象尚未被session 载入过,那么对象通过 SELECT ... FOR UPDATE 这样的 SQL 语句被载入。如果为一个对象调用 load() 方法时,该对象已经在另一个较少限制的锁定模式下被载入了,那么 Hibernate 就对该对象调用 lock() 方法。
如果指定的锁定模式是 READ,UPGRADE 或 UPGRADE_NOWAIT,那么 Session.lock() 就执行版本号检查。(在 UPGRADE 或者 UPGRADE_NOWAIT 锁定模式下,执行 SELECT ... FOR UPDATE这样的SQL语句。)
如果数据库不支持用户设置的锁定模式,Hibernate 将使用适当的替代模式(而不是扔出异常)。这一点可以确保应用程序的可移植性。
例:利用悲观锁协调并发执行的取款事务和支票转账事务
Account account=(Account)session.get
(Account.class,new Long(1), LockMode.UPGRADE);
account.setBalance(account.getBalance()-100);
Hibernate执行的select语句为:
select * from ACCOUNTS where ID=1 for update;
update ACCOUNTS set BALANCE=900…
2.Optimistic Locking 乐观锁:
乐观锁定(optimistic locking)则乐观的认为资料的存取很少发生同时存取的问题,因而不作数据库层次上的锁定,为了维护正确的数据,乐观锁定采用应用程序上的逻辑实现版本控制的方法。
•乐观锁是由应用程序提供的一种机制,这种机制既能保证多个事务并发访问数据,又能防止第二类丢失更新问题。
•在应用程序中,可以利用Hibernate提供的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>元素都具有版本控制功能:
–<version>元素利用一个递增的整数来跟踪数据库表中记录的版本
–<timestamp>元素用时间戳来跟踪数据库表中记录的版本。
例:使用<version>元素实现对ACCOUNTS表中的记录进行版本控制:
•(1)在Account类中定义一个代表版本信息的属性:
private int version;
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
•(2)在ACCOUNTS表中定义一个代表版本信息的字段。
•(3)在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射:
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<version name="version" column="VERSION" />
……
•当Hibernate更新一个Account对象时,会根据它的id与version属性到ACCOUNTS表中去定位匹配的记录,假定Account对象的version属性为0,那么在取款事务中Hibernate执行的update语句为:
update ACCOUNTS set NAME=’Tom’,BALANCE=900,VERSION=1 where ID=1 and VERSION=0;
•如果存在匹配的记录,就更新这条记录,并且把VERSION字段的值加1。当支票转账事务接着执行以下update语句时:
update ACCOUNTS set NAME=’Tom’,BALANCE=1100,VERSION=1 where ID=1 and VERSION=0;
•由于ID为1的ACCOUNTS记录的版本已经被取款事务修改,因此找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException。
利用乐观锁协调并发执行的取款事务和支票转账事务:
•在应用程序中应该捕获该异常,这种异常有两种处理方式:
–方式一:自动撤销事务,通知用户账户信息已被其他事务修改,需要重新开始事务。
–方式二:通知用户账户信息已被其他事务修改,显示最新存款余额信息,由用户决定如何继续事务,用户也可以决定立刻撤销事务。
try { tx = session.beginTransaction(); log.write("transferCheck():开始事务"); Thread.sleep(500); Account account=(Account)session.get(Account.class,new Long(1)); log.write("transferCheck():查询到存款余额为:balance="+account.getBalance()); Thread.sleep(500); account.setBalance(account.getBalance()+100); log.write("transferCheck():汇入100元,把存款余额改为:"+account.getBalance()); tx.commit(); //当Hibernate执行update语句时,可能会抛出StaleObjectException log.write("transferCheck():提交事务"); Thread.sleep(500); }catch(StaleObjectStateException e){ if (tx != null) { tx.rollback(); } e.printStackTrace(); System.out.println("账户信息已被其他事务修改,本事务被撤销,请重新开始支票转账事务"); log.write("transferCheck():账户信息已被其他事务修改,本事务被撤销"); }
实现乐观锁的其它方法:
•如果应用程序是基于已有的数据库(如遗留项目),而数据库表中不包含代表版本或时间戳的字段,Hibernate提供了其他实现乐观锁的办法。把<class>元素的optimistic-lock属性设为“all”:
<class name="Account" table="ACCOUNTS" optimistic-lock="all" dynamic-update="true">
•Hibernate会在update语句的where子句中包含Account对象被加载时的所有属性:
update ACCOUNTS set BALANCE=900 where ID=1 and NAME='Tom' and BALANCE='1000';
(参考风中叶张龙老师教学课件)
转载请注明出处:http://blog.csdn.net/jialinqiang/article/details/8723051