hibernate之控制并发访问(乐观并发控制之外获得额外的隔离性保证)

hibernate之控制并发访问(乐观并发控制之外获得额外的隔离性保证)

显式的悲观锁
已经讨论了把所有的数据库连接转换到一个比读取提交更高的隔离性级别,但我们的结论是,当关注应用程序的可伸缩性时,这则是一项糟糕的默认。你需要更好,仅用于一个特定的工作单元的隔离性保证。还要记住,持久化上下文高速缓存为处于持久化状态的实体实例提供可重复读取。然而,这并非永远都是足够的。例如,对标量查询可能需要可重复读取:
 
这个工作单元执行两次读取。第一次通过标识符获取实体实例。第二次读取标量查询,再次加载已经加载的Item实体的描述。在这个工作单元中有一个小窗口,在那里,并发运行的事务可以在两次读取之间提供一个更新过的货品描述。然后第二次读取返回这个提交数据,且变量description有一个与属性i.getDescription()不同的值。
这个例子进行过简化,但仍然足以说明:如果数据库事务隔离性级别是读取提交,那么混有实体和标量读取的工作单元有多么容易受到不可重复读取的影响。
不是把所有的数据库事务转换为一个更高的,不可伸缩的隔离性级别,而是在必要时,在hibernate Session中使用lock()方法获得更强的隔离性保证:
 
使用LockMode.UPGRADE,给表示Item实例的(多)行,促成了在数据库中保存的悲观锁。现在没有并发事务可以在相同数据中获得锁---也就是说,没有并发事务可以在你的两次读取之间修改数据。这段代码可以被缩短成如下:
 
LockMode.UPGRADE导致一个SQL SELECT ... FOR UPDATE或者类似的东西,具体取决于数据库方言。一种变形
LockMode.UPGRADE_NOWAIT,添加了一个允许查询立即失败的子句。如果没有这个子句,当无法获得锁时(可能由于一个并发事务已经有锁),数据库通常会等待。等待的持续时间取决于数据库,就像实际的SQL子句一样。
-------------------
hibernate锁模式
hibernate支持下列其他LockMode:
. LockMode.NONE---别到数据库中去,除非对象不处于任何高速缓存中。
. LockMode.READ---绕过所有高速缓存,并执行版本检查,来验证内存中的对象是否与当前数据库中存在的版本相同。
. LockMode.UPGRADE---绕过所有高速缓存,做一个版本检查(如果适用),如果支持的话,就获得数据库级的悲观升级锁。如果数据 库方言 不支持SELECT ... FOR UPDATE选项,这个模式就透明地退回到LockMode.READ。
. LockMode.UPGRADE_NOWAIT---与UPGRADE相同,但如果支持的话,就使用SELECT ... FOR UPDATE NOWAIT。它禁用了等 待并发 锁释放,因而如果无法获得锁,就立即抛出锁异常。如果数据库SQL方言不支持NOWAIT选项,这个模式就透明地退回到LockMode.UPGRADE。
. LockMode.FORCE---在数据库中强制增加对象的版本,来表明它已经被当前事务修改。
. LockMode.WRITE---当hibernate已经在当前事务中写到一个行时,就自动获得它。(这是一种内部模式:你不能在应用程序中指定它)
默认情况下,load()和get()使用LockMode.NONE。LockMode.READ对session.lock()和脱管对象最有用。这里有个例子:
 
这段代码在通过级联(假设从Item到Bid的关联启用了级联)保存新Bid之前,在脱管的Item实例上执行版本检查,验证该数据库行在获取之后没有被另一个事务更新。
-----------------
强制增加版本
如果通过版本控制启用乐观锁,hibernate会自动增加被修改实体实例的版本。然而,有时你想手工增加实体实例的版本,因为hibernate不会把你的改变当成一个应该触发版本增加的修改。如例,想象你修改了CreditCard所有者的名称:
 
当这个Session被清除时,被修改的BillingDetails实例(我们假设是一张信用卡)的版本通过hibernate自动增加了。这可能并不是你想要的东西---你可能也想增加所有者(User实例)的版本。如例,用LockMode.FORCE调用lock(),增加一个实体实例的版本:
 
现在,任何使用相同User行的并发单元都知道这个数据被修改了,即使只有被你认为是整个聚合的一部分的其中一个值被修改了。这种技术在许多情况下都有用,例如当你修改一个对象并且想要增加聚合的根对象版本时。另一个例子是对一件拍卖货品出价金额的修改(如果这些金额是不可变的),利用一个显式的版本增加,可以指出这件货品已经被修改,即使它的值类型属性或者集合都没有发生改变。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值