oracle中记录被另一个用户锁住的原因与解决

一、原因

    数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

二、原理

1.UPDATE/DELETE操作会将RS锁定,直至操作被COMMIT或者ROLLBACK;
若操作未COMMIT之前其他session对同样的RS做变更操作,则操作会被hold,
直至前session的UPDATE/DELETE操作被COMMIT;

2.session内外SELECT的RS范围
前提:INSERT、UPDATE操作未COMMIT之前进行SELECT;
若在同一session内,SELECT出来的RS会包括之前INSERT、UPDATE影响的记录;
若不在同一session内,SELECT出来的RS不会包括未被COMMIT的记录;

3.SELECT.... FOR UPDATE [OF cols] [NOWAIT/WAIT] [SKIP LOCKED]
OF cols:只锁定指定字段所在表的RS,而没有指定的表则不会锁定,只会在多表联合查询时出现;
NOWAIT:语句不会hold,而是直接返回错误ORA-00054: resource busy and acquire with NOWAIT specified;
WAIT N:语句被hold N秒,之后返回错误ORA-30006: resource busy; acquire with WAIT timeout expired;
SKIP LOCKED:不提示错误,而是直接返回no rows selected;
以上几个选项可以联合使用的,比较推荐的有:
SELECT.... FOR UPDATE NOWAIT:对同一RS执行该SQL时,直接返回错误;
SELECT.... FOR UPDATE NOWAIT SKIP LOCKED:对同一RS执行该SQL时,直接返回空行;
PS:当RS被LOCK住之后,只对同样请求LOCK的语句有效,对无需LOCK的SELECT语句并没有任何影响;

三、解决方法(记录被另一个用户锁住)

1、查看数据库锁,诊断锁的来源及类型

select object_id,session_id,locked_mode from v$locked_object; 
或者用以下命令:
select b.owner,b.object_name,l.session_id,l.locked_mode from v$locked_object l,
 dba_objects b where b.object_id=l.object_id 

2、找出数据库的serial#,以备杀死

select t2.username,t2.sid,t2.serial#,t2.logon_time from v$locked_object t1,
v$session t2 where t1.session_id=t2.sid order by t2.logon_time;

3、杀死该session   

alter system kill session 'sid,serial#'

四、补充

for update 与 rowid 的区别

for update:
当语句运行时,会在对应行(where子句)加上行级锁,无where子句等于全表上锁。若遇到客户端断网、
测试人员忘记提交/回滚事务,则会发生锁表。 
rowid: 运行后并未给数据加上行级锁(通过物理地址去确定某一行数据),但可以编辑数据,
提交事务的瞬间完成上锁、提交、解锁等动作,不易发生锁表。

引用地址:http://blog.csdn.net/huoliya12/article/details/50955552

猜你喜欢

转载自my.oschina.net/HarleyZhuge/blog/1632625