游标SELECT操作将不会对正处理的行执行任何锁定设置,这使得连接到该数据库的其他会话可以改变正在选择的数据,使用FOR UPDATE子句,在OPEN返回以前的活动集的相应行上会加上互斥锁,这些锁会避免其他的会话对活动集中的行进行更改。直到整个事务被提交为止。
示例:
DECLARE cur CURSOR FOR SELECT * FROM [Table]
FOR UPDATE OF [Table.col]
OPEN cur
WHILE @@FETCH_STATUS=0
BEGIN
UPDATE [Table] SET [Table.col] WHILE CURRENT OF cur
END
CLOSE cur
DEALLOCATE cur
lock相应情况:
update, insert ,delete, select ... for update会LOCK相应的ROW 。
只有一个TRANSACTION可以LOCK相应的行,也就是说如果一个ROW已经LOCKED了,那就不能被其他TRANSACTION所LOCK了。
LOCK由statement产生但却由TRANSACTION结尾(commit,rollback),也就是说一个SQL完成后LOCK还会存在,只有在COMMIT/ROLLBACK后才会RELEASE。
SELECT.... FOR UPDATE [OF cols] [NOWAIT]; OF cols SELECT cols FROM tables [WHERE...] FOR UPDATE [OF cols] [NOWAIT]; |
前面的FOR UPDATE省略,下面我们来讲一下OF。
transaction A运行 select a.object_name,a.object_id from wwm2 a,wwm3 b 2 where b.status='VALID' and a.object_id=b.object_id 3* for update of a.status |
则transaction B可以对b表wwm3的相应行进行DML操作,但不能对a表wwm2相应行进行DML操作.
反一下看看。
transaction A运行 select a.object_name,a.object_id from wwm2 a,wwm3 b 2 where b.status='VALID' and a.object_id=b.object_id 3* for update of b.status |
则transaction B可以对a表wwm2的相应行进行DML操作,但不能对b表wwm3相应行进行DML操作.
也就是说LOCK的还是行,只是如果不加OF的话会对所有涉及的表LOCK的,加了OF后只会LOCK OF 字句所在的TABLE.
NOWAIT(如果一定要用FOR UPDATE,我更建议加上NOWAIT)
当有LOCK冲突时会提示错误并结束STATEMENT而不是在那里等待.返回错误是"ORA-00054: resource busy and acquire with NOWAIT specified"
另外如下用法也值得推荐,应该酌情考虑使用。
FOR UPDATE WAIT 5 |
ORA-30006: resource busy; acquire with WAIT timeout expired FOR UPDATE NOWAIT SKIP LOCKED; |
no rows selected TABLE LOCKS LOCK TABLE table(s) IN EXCLUSIVE MODE [NOWAIT]; |
同样也是在transaction结束时才会释放lock。
DEADLOCK:
transaction a lock rowA , then transaction b lock rowB then transaction a tries to lock rowB, and transaction b tries to lock rowA |
也就是说两个transaction都相互试图去lock对方已经lock的ROW,都在等待对方释放自己的lock,这样就使死锁。另外,deadlock也会有600提示。