oracle数据库:锁和闩_笔记3
乐观锁定
第二种方法称为乐观锁定(optimistic locking),即把所有锁定都延迟到即将执行更新之前才做,换句话说,我们会修改屏幕上的信息而不要锁。我们很乐观,认为数据不会被其他用户修改。因此,会等到最后一刻才去看我们的想法对不对。
这种锁定的方法在所有环境下都行得通,但是采用这种方法的话,执行更新的用户“失败”的可能性会加大。这说明,这个用户要更新他的数据行时,发现数据已经修改过,所以他必须从头再来。
可以在应用中同时保留旧值和新值,然后在更新数据时使用如下的更新语句,这是乐观锁定的一种流行实现:
Update table
Set column1 = :new_column1,column2 = :new_column2,...
Where primary_key = :primary_key
And decode(column1, :old_column1,1) =1
And decode(column2, :old_column2,1) =1
...
在此,我们乐观的认为数据没有修改。在这种情况下,如果更新语句更新了一行,那我们很幸运,这说明,在读数据和提交更新之间,数据没有改变。但是如果更新了零行,我们就会失败。另外一个人已经修改了数据,现在我们必须确定应用中下一步要做什么。
实际上,前面的UPDATE能避免丢失更新,但是确实有可能被阻塞,在等待另一个会话执行对这一行的UPDATE时,它会挂起。如果所有应用(会话)都使用乐观锁定,那么使用直接的UPDATE一般没什么问题,因为执行更新并提交时,行只会被锁定很短的时间。不过,如果某些应用使用了悲观锁定,它会在一段相对较长的时间内持有行上的锁,或者如果有应用(如批处理进程)可能锁定行很长时间(不止一两秒),那么你可能就会考虑使用SELECT FOR UPDATE NOWAIT,以此来验证行是否未被修改,并在即将UPDATE之前锁定来避免被另一个会话阻塞。
实现乐观并发控制的方法有很多种。我们已经讨论了这样的一种方法,即应用本身会存储行的所有“前”(before)映像。将介绍另外两种方法。
.使用一个特殊的列,这个列由一个数据库解发器或应用程序代码维护,可以告诉我们记录的“版本”。
.使用一个校验和或散列值,这是使用原来的数据计算得出的。
使用版本列的乐观锁定
这是一个简单的实现,如果你想保护数据库表不出现丢失更新问题,应对每个要保护的表增加一列。这一列一般是NUMBER或DATE/TIMESTAMP列,通常通过表上的一个行触发器来维护。每次修改行时,这个触发器要负责递增NUMBER列中的值,或者更新DATE/TIMESTAMP列。
如果应用要实现乐观并发控制,只需要保存这个附加列的值,而不需要保存其他列的所有“前”映像。应用只需验证请求更新那一刻,数据库中这一列的值与最初读出的值是否匹配。如果两个值相等,就说明这一行未被更新过。
TIMESTAMP数据类型在Oracle中精度最高,通常可以精确到微秒(百万分之一秒)。如果应用要考虑到用户的思考时间,这种TIMESTAMP级的精度实在是绰绰有余,而且数据库获取一行后,人看到这一行,然后修改,再向数据库发回更新,一般不太可能在不到1秒钟的片刻时间内执行整个过程。两个人在同样短的时间内(不到1秒钟)读取和修改同一行的几率实在太小了。
接下来,需要一种方法来维护这个值。我们有两种选择:可以由应用维护这一列,更新记录时将LAST_MOD列的值设置为SYSTIMESTAMP;也可以由触发器/存储过程来维护。如果让应用维护,比基于触发器的方法表现更好,因为触发器会代表Oracle对修改增加额外的处理。不过,这并不是说:无论什么情况,都要依赖所有应用在表中经过修改的所有位置上一致地维护LAST_MOD。所以,如果要由各个负责维护这个字段,就需要一致地验证LAST_MOD列未被修改,并把LAST_MOD列设置为当前的SYSTIMESTAMP。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/5193.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
