阻塞(blocking)(第6章.锁)

Expert Oracle Database Architecture学习笔记

阻塞(blocking)(第6章.锁)


如果一个会话持有某个资源的锁,而另一个会话在请求这个资源,就会出现阻塞(blocking)。几乎在所有情况下,阻塞都是可以避免的。实际上,如果你真的发现会话在一个交互式应用中被阻塞,就说明很可能同时存在着另一个bug,即丢失更新。也就是说,你的应用逻辑有问题,这才是阻塞的根源。

数据库中有5条常见的DML语句可能会阻塞,具体是:INSERT、UPDATE、DELETE、MERGE和SELECT FOR UPDATE。
1、对于阻塞的SELECT FOR UPDATE,解决方法很简单,只需增加NOWAIT子句,他就不会阻塞了,他会向你报告,这一行已经锁定。

2、阻塞的insert
insert的阻塞不多见。最常见的情况是,你有一个带主键的表,或者表上有唯一的约束,但两个会话试图用同样的值插入一行。如果这样,其中的一个会话就会阻塞,直到另一个会话提交或者回滚为止:如果另一个会话提交,则阻塞的会话会收到一个错误,指出存在一个重复值;倘若另一个会话会滚,则阻塞的会话会成功。还有一种情况,可能多个表通过引用完整性约束相互链接。对子表的插入可能会阻塞,因为它所依赖的父表正在创建或删除。

如果允许最终用生成主键/唯一列值,就有可能发生insert阻塞。为避免这种情况,最容易的做法是使用一个序列来生成主键/唯一列值。

如果无法使用序列,可以使用手工锁来避免这个问题,这里的手工锁通过内置的DBMS_LOCK包来实现。
(这个问题挺有意思,以后再回过头来专门研究)

3、阻塞的Merge、Update和Delete
在一个交互式应用中,可以从数据库查询某个数据,允许最终用户处理这个数据,再把它“放回”到数据库中。此时如果Update或Delete阻塞,就说明你的代码中可能存在一个丢失更新的问题(按Tom的说法,这就是你代码中的bug)。你试图更新其他人正在更新的行。通过使用select for update nowait查询可以避免这个问题,这个查询能做到:
·验证自从你查询数据之后数据未被修改(防止丢失更新)
·锁住行(防止Update或Delete被阻塞)

不管是悲观锁定还是乐观锁定都可以利用select for update nowaut查询来验证行未被修改。悲观锁定会在用户有意修改数据那一刻使用这条语句。乐观锁定则在即将在数据库中更新数据时使用这条语句。这样不仅能解决应用中的阻塞问题,还可以修正数据完整性问题。

由于Marge只是insert 和 update(如果在10g中采用改进的Marge语法,还可以是delete),所以可以同时使用这两种技术。

你可能感兴趣的:(block)