oracle 锁和闩_笔记5:阻塞情况分析
阻塞
如果一个会话持有某个资源的锁,而另一个会话在请求这个资源,就会出现阻塞(blocking)。这样一来,请求的会话会被阻塞,它会“挂起”,直至持有锁的会话放弃锁定的资源。几乎在所有情况下,阻塞都是可以避免的。实际上,如果你真的发现会话在一个交互式应用中被阻塞,就说明很有可能同时存在着另一个bug,即丢失更新,只不过你可能没有意识到这一点。也就是说,你的应用逻辑有问题,这才是阻塞的根源。
数据库中有5条常见的DML语句可能会阻塞,具体是:INSERT、UPDATE、DELETE、MERGE和SELECT FOR UPDATE。对于一个阻塞的SELECT FOR UPDATE,解决方案很简单:只需增加NOWAIT子句,它就不会阻塞了。这样一来,你的应用会向最终用户报告,这一行已经锁定。
1.阻塞的INSERT
INSERT阻塞的情况不多见。最常见的情况是,你有一个带主键的表,或者表上有唯一的约束,但有两个会话试图用同样的值插入一行。如果是这样,其中一个会话就会阻塞,直到另一个会话提交或者回滚为止:如果另一个会话提交,那么阻塞的会话会收到一个错误,指出存在一个重复值;倘若另一个会话回滚,在这种情况下,阻塞的会话则会成功。还有一种情况,可能多个表通过引用完整性约束相互链接。对子表的插入可能会阻塞,因为它所依赖的父表正在创建或删除。
如果应用允许最终用户生成主键/唯一列值,往往就会发生INSERT阻塞。为避免这种情况,最容易的做法是使用一个序列或SYS_GUID()来生成主键/唯一列值。序列(sequence)内建函数设计为一种高度并发的方法,用在多用户环境中生成唯一键。如果都无法使用,并且必须允许最终用户生成可能被复制的键,可以使用以下技术,也就是手工锁来避免这个问题,这里的手工锁通过内置的DBMS_LOCK包来实现。
对于插入,不会选择现有的行,也不会对现有的行锁定。没有办法避免其他人插入值相同的行,如果别人真的插入了具有相同值的行,这会阻塞我们的会话,而导致我们无休止地等待。此时,DBMS_LOCK就能派上用场了。
2.阻塞的Merge、Update和Delete
在一个交互式应用中,可以从数据库查询某个数据,允许最终用户处理这个数据,再把它“放回”到数据库中,此时如果UPDATE或DETELE阻塞,就说明你的代码中可能存在一个丢失更新问题(如果真是这样,按我的说法,就是你的代码中存在bug)。你试图UPDATE(更新)其他人正在更新的行(换句话说,有人已经锁住了这一行)。通过使用SELECT FOR UPDATE NOWAIT查询可以避免这个问题,这个查询能做到:
.验证自从你查询数据之后数据未被修改(防止丢失更新)
.锁住行(防止UPDATE或DELETE被阻塞)
如前所述,不论采用哪一种锁定方法都可以这样做。不论是悲观锁定还是乐观锁定都可以利用SELECT FOR UPDATE NOWAIT查询来验证行未被修改。悲观锁定会在用户有意修改数据那一刻使用这条语句。乐观锁定则在即将在数据库中更新数据时使用这条语句。这样不仅能解决应用中的阻塞问题,还可以修正数据完整性问题。
由于MERGE只是INSERT和UPDATE(如果在10g及更高版本中采用改进的MERGE语法,还可以是DELETE),所以可以同时使用这两种技术。
本文来源 我爱IT技术网 http://www.52ij.com/jishu/5196.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
