oracle报错:ORA-01013: user requested cancel of current operation
分析: 一般是因为update的时候被锁定了。
使用有解锁权限的用户,解锁即可。
SELECT
s.username, -- 用户(表空间)
s.sid, -- session_id
s.serial#, -- serial# 是序列号
s.logon_time, -- 登录时间
l.locked_mode
FROM
v$session s, -- v$Session 是session视图
v$locked_object l
WHERE
s.sid = l.session_id
ORDER BY
s.logon_time;
dba_objects.object_name可以显示对象名等,如表名。这样在kill的时候更有把握些。
SELECT
s.sid, -- session_id
s.serial#, -- serial# 是序列号
s.username, -- 用户(表空间)
s.logon_time, -- 登录时间
o.owner,
o.object_name
FROM
v$session s, -- v$Session 是session视图
v$locked_object l,
dba_objects o
WHERE
s.sid = l.session_id
and l.object_id = o.object_id
ORDER BY
s.logon_time;
alter system kill session '5633,12566'; -- sid和serial# 共同确定一条数据
实测可用, 如果session不是很多,建议一个一个kill。
select
a.object_name,b.session_id,c.serial#,
'alter system kill session '''||b.session_id||','||c.serial#||'''; ' as a,
c.program,c.username,c.command,c.machine,c.lockwait
from all_objects a,v$locked_object b,v$session c
where a.object_id=b.object_id and c.sid=b.session_id;
通过kill的方法,可以临时解决锁表问题,但不是长久办法,最好是找到锁表的语句,从根本上解决问题。
分为2部分,一部分阻塞blocking。一部分是被阻塞(blocked)。要看2个,union all即可。
要用到3个视图: lock,session,sql。
有2点需要注意:
1、s.prev_sql_id = sq.sql_id 用prev_sql_id关联 sq.sql_id
2、l.block =‘1’ block值为1,表示阻塞别人
select
decode(l.block, 1, 'blocking') blocking, -- block(是否阻塞他人) 0不阻塞 1阻塞
decode(l.request, 0, 'null', 'blocked') blocked, -- request(是否被阻塞) 0没被阻塞 1-6被阻塞
l.request,
s.sid, s.username, s.logon_time, s.machine,
sq.sql_id, sq.sql_text, sq.hash_value, sq.module
from v$lock l, v$session s, v$sql sq
where 1 = 1
and l.sid = s.sid
and s.prev_sql_id = sq.sql_id
and l.block ='1';
select
decode(l.block, 1, 'blocking') blocking, -- block(是否阻塞他人) 0不阻塞 1阻塞
decode(l.request, 0, 'null', 'blocked') blocked, -- request(是否被阻塞) 0没被阻塞 1-6被阻塞
l.request,
s.sid, s.machine, s.username, s.logon_time,
sq.sql_id, sq.sql_text, sq.hash_value, sq.module
from v$lock l, v$session s, v$sql sq
where 1 = 1
and l.type ='TX'
and l.sid = s.sid
and s.sql_id = sq.sql_id;
lock和session始终用sid关联即可(以下2条件一般不用变):
l.type ='TX'
l.sid = s.sid
blocking有2个注意点:
1、block=‘1’ 1表示阻塞了别人。
2、要用prev_sql_id 去关联,因为它最近执行的语句阻塞了别人。
block='1'
s.pre_sql_id= sq.sql_id
blocked注意点:
1、这里要看request字段,不是0的话,表示该sql请求 被阻塞了。
不要看block字段,因为block是是否阻塞别人。 在这里用不到。
2、用sql_id关联即可。因为就是当前sql被阻塞了。
-- 注: 这里不用加 block = '1' 字段
s.sql_id = sq.sql_id
值得一提的是。 不仅可以根据sql_id关联,通过address也是可以关联的,效果一样。
blocking中这么写:
block='1'
s.pre_sql_address= sq.sql_address
blocked中这么写:
s.sql_address= sq.address
使用pl/sql等工具模拟阻塞的时候会出现这个。显示的pl/sql中session创建的事务信息。
如果在sqlplus中直接执行命令。 那么是可以显示原语句的。
有兴趣可以自己试一下:
cmd打开2个窗口,链接oracle并分别执行语句:
第一个cmd窗口:
sqlplus / as sysdba;
conn root/666666@47.104.176.200/helowin; -- 如果是本地,@后面的可以省略
savepoint a; -- 设置保存点a,相当于开启事务
select * from t_user for update; -- 锁住全表
第二个cmd窗口:
-- 链接命令同上,略
savepoint a;
select * from t_user where id = '1' for update; -- 这条被阻塞
然后执行 查看阻塞他人的语句 会显示 select * from t_user for update;
说明是原语句。
如果要显示pl/sql中的原语句,要看trace了,略。
select sql_text from v$sql where hash_value in
(
select sql_hash_value from v$session where sid in
(
select session_id from v$locked_object
)
);
select b.sid,
a.sql_id,
a.sql_text,
a.hash_value,
b.username,
b.machine,
a.module,
decode(c.block, 1, 'blocking') blocking,
decode(c.request, 0, 'null', 'blocked') blocked,
to_char(b.logon_time, 'yyyy-mm-dd hh24:mi:ss')
from v$sql a, v$session b, v$lock c
where c.type = 'TX'
and a.sql_id = b.sql_id
and b.sid = c.sid
union all
select b.sid,
a.sql_id,
a.sql_text,
a.hash_value,
b.username,
b.machine,
a.module,
decode(c.block, 1, 'blocking') blocking,
decode(c.request, 0, 'null', 'blocked') blocked,
to_char(b.logon_time, 'yyyy-mm-dd hh24:mi:ss')
from v$sql a, v$session b, v$lock c
where c.type = 'TX'
and a.sql_id = b.prev_sql_id
and b.sid = c.sid
and c.block = 1;
lb,sb,qb b表示blocker。 l,s,q 是lock,session,sql 。
lw,sw,qw w表示waiter。l,s,q 是lock,session,sql 。
|| 是字符串连接符。
select
'blocker('||lb.sid||':'||sb.username||')-sql:'|| qb.sql_text blockers,
'waiter ('||lw.sid||':'||sw.username||')-sql:'|| qw.sql_text waiters
from v$lock lb,
v$lock lw,
v$session sb,
v$session sw,
v$sql qb,
v$sql qw
where lb.sid=sb.sid
and lw.sid=sw.sid
and sb.prev_sql_addr=qb.address
and sw.sql_address=qw.address
and lb.id1=lw.id1
and sw.lockwait is not null
and sb.lockwait is null
and lb.block=1 ;
都是通过object_id来关联的。
SELECT
o.owner,
o.object_name,
l.session_id,
l.locked_mode
FROM
v$locked_object l,
dba_objects o
WHERE
o.object_id = l.object_id;
/*+ rule */ 这种写法有助于效率提升。
select
/*+ rule */ lpad(' ', decode(l.xidusn, 0, 3, 0)) || l.oracle_username user_name,
o.owner, o.object_name, o.object_type, s.sid, s.serial#, p.spid
from v$locked_object l, dba_objects o, v$session s, v$process p
where l.object_id = o.object_id and l.session_id = s.sid and s.paddr = p.addr
order by o.object_id, xidusn desc;
select
s.status,s.sid,s.serial#,p.spid,
s.last_call_et as exec_seconds,t.sql_text as curr_sql
from gv$session s,v$process p,v$instance i,v$lock k, v$sqltext t
where s.paddr = p.addr
and s.type != 'BACKGROUND'
and s.lockwait = k.kaddr
and s.sql_hash_value = t.hash_value
and s.username is not null;