ITPUB论坛-中国专业的IT技术社区

 找回密码
 注册
查看: 4186|回复: 6

[每日一题] PL/SQL Challenge 每日一题:2018-3-30 DBMS_LOCK

[复制链接]
论坛徽章:
496
紫蜘蛛
日期:2007-09-26 17:05:56奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:53
发表于 2018-4-7 04:09 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。

每两周的优胜者可获得itpub奖励的技术图书一本。

以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808

原始出处:
http://www.plsqlchallenge.com/

作者: Elic

运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品

我执行了下列语句:

create package qz_Lock authid definer as
  procedure ShowTransaction(p_Action varchar2);
  procedure Request(p_ReleaseOnCommit boolean := true);
  procedure Release;
end qz_Lock;
/

create package body qz_Lock as
  type TStrs is table of varchar2(100);
  g_LockHandle varchar2(128);

procedure ShowTransaction(p_Action varchar2) is
begin
  dbms_output.put_line ( p_Action || '. Transaction is '
    || nvl(dbms_transaction.local_transaction_id, 'none')
  );
end ShowTransaction;

procedure Request(p_ReleaseOnCommit boolean := true)
is
  l_LockStatus int;
begin
  ShowTransaction('Requesting lock');
  l_LockStatus := dbms_lock.request
    ( g_LockHandle
    , lockmode=>dbms_lock.x_mode
    , timeout=>0
    , release_on_commit=>p_ReleaseOnCommit
    );
  if l_LockStatus <> 0 then
    raise_application_error ( -20000
    , 'dbms_lock.request returned ' || l_LockStatus || ' - ' ||
        TStrs('timeout', 'deadlock', 'parameter error', 'already own', 'illegal lockhandle')
             (l_LockStatus)
    );
  end if;
end Request;

procedure Release
is
  l_LockStatus int;
begin
  ShowTransaction('Releasing lock');
  l_LockStatus := dbms_lock.release(g_LockHandle);
  if l_LockStatus <> 0 then
    raise_application_error ( -20000
    , 'dbms_lock.release returned ' || l_LockStatus || ' - ' ||
        TStrs('', '', '', 'don`t own', 'illegal lockhandle')
             (l_LockStatus)
    );
  end if;
end Release;

procedure Initialize is
  pragma autonomous_transaction;
begin
  dbms_lock.allocate_unique('qz_Lock', g_LockHandle);
end Initialize;

begin
  Initialize;
end qz_Lock;
/

create table qz_tab(i int not null);

create trigger qz_tab$bi$trg before insert on qz_tab
begin
  qz_Lock.Request;
end;

下列哪些选项在执行的时候不会报异常?

注意:ShowTransaction过程只是用于解释,而不会影响选项的正确性。

(A)
begin
  qz_Lock.Request;
  qz_Lock.Release;
end;
/

(B)
begin
  qz_Lock.Request;
  qz_Lock.Request;
  qz_Lock.Release;
end;
/

(C)
begin
  qz_Lock.Request;
  qz_Lock.Request(p_ReleaseOnCommit=>false);
  qz_Lock.Release;
end;
/

(D)
begin
  qz_Lock.Request;
  commit;
  qz_Lock.Release;
end;
/

(E)
begin
  qz_Lock.Request;
  rollback;
  qz_Lock.Release;
end;
/

(F)
begin
  savepoint BeforeLock;
  qz_Lock.ShowTransaction('Savepoint BeforeLock');
  qz_Lock.Request;
  rollback to BeforeLock;
  qz_Lock.Release;
end;
/

(G)
begin
  qz_Lock.Request;
  savepoint BeforeRelease;
  qz_Lock.ShowTransaction('Savepoint BeforeRelease');
  qz_Lock.Release;
  rollback to BeforeRelease;
  qz_Lock.Release;
end;
/

(H)
begin
  set transaction read write;
  qz_Lock.ShowTransaction('Before insert');
  insert into qz_tab values(null);
exception
  when others then
    dbms_output.put_line(sqlerrm);
    qz_Lock.Request;
end;
/

(I)
begin
  qz_Lock.ShowTransaction('Before insert');
  insert into qz_tab values(null);
exception
  when others then
    dbms_output.put_line(sqlerrm);
    qz_Lock.Request;
end;
/

(J)
begin
  set transaction read write;
  qz_Lock.ShowTransaction('Before insert');
  insert into qz_tab values(null);
exception
  when others then
    dbms_output.put_line(sqlerrm);
    qz_Lock.Release;
end;
/

(K)
begin
  qz_Lock.ShowTransaction('Before insert');
  insert into qz_tab values(null);
exception
  when others then
    dbms_output.put_line(sqlerrm);
    qz_Lock.Release;
end;
/

(L)
declare
  procedure Auto
  is
    pragma autonomous_transaction;
  begin
    qz_Lock.Request;
  end Auto;
begin
  qz_Lock.Request;
  Auto;
end;
/

(M)
declare
  procedure Auto
  is
    pragma autonomous_transaction;
  begin
    qz_Lock.Release;
  end Auto;
begin
  qz_Lock.Request;
  Auto;
end;
/

(N)
declare
  procedure Auto
  is
    pragma autonomous_transaction;
  begin
    qz_Lock.Release;
  end Auto;
begin
  qz_Lock.Request(p_ReleaseOnCommit=>false);
  Auto;
end;
/

论坛徽章:
11
懒羊羊
日期:2018-02-27 22:52:20秀才
日期:2018-05-22 15:17:21技术图书徽章
日期:2018-05-22 15:17:21秀才
日期:2018-05-22 15:16:47举人
日期:2018-03-01 10:25:45秀才
日期:2018-03-01 10:21:25秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:05:18
发表于 2018-4-9 09:21 | 显示全部楼层
create trigger qz_tab$bi$trg ...  这个$符代表啥意思啊

使用道具 举报

回复
求职 : 数据库开发
论坛徽章:
23
秀才
日期:2017-08-11 15:38:46秀才
日期:2018-01-02 15:17:54秀才
日期:2018-01-02 15:18:22秀才
日期:2018-01-02 15:18:22秀才
日期:2018-01-02 15:18:22秀才
日期:2018-01-02 15:18:22秀才
日期:2018-01-02 15:18:22技术图书徽章
日期:2018-01-02 15:18:30秀才
日期:2018-03-01 10:05:18秀才
日期:2018-05-22 15:21:20
发表于 2018-4-9 10:11 | 显示全部楼层
a875458744 发表于 2018-4-9 09:21
create trigger qz_tab$bi$trg ...  这个$符代表啥意思啊

没有特别的意思 你可以把它当成下划线

使用道具 举报

回复
论坛徽章:
496
紫蜘蛛
日期:2007-09-26 17:05:56奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:53
 楼主| 发表于 2018-4-10 04:52 | 显示全部楼层
答案AFIJN,本期无人参与。

A: 这是用户自定义锁的普通流程:获取一个锁,执行重要任务,然后释放锁。这个可以执行不出错。
B: 和SELECT FOR UPDATE不同的是,第二个锁的结果和第一个不同。这会报错:
ORA-20000: dbms_lock.request returned 4 - already own
C: 我们不能将一个锁的范围从事务改成会话。这会得到和前一选项一样的错误。
D:
COMMIT结束了一个事务,并且自动释放所有事务锁。所以releas报错:

ORA-20000: dbms_lock.release returned 4 - don`t own

F: ROLLBACK TO SAVEPOINT 并不会结束事务。用户锁仍然活跃,release成功了。这个选项会显示:

Savepoint BeforeLock. Transaction is 9006.19.7061
Requesting lock. Transaction is 9006.19.7061
Releasing lock. Transaction is 9006.19.7061

PL/SQL procedure successfully completed.

G:  ROLLBACK TO SAVEPOINT 不能恢复已释放的锁。这个选项会报错:

Requesting lock. Transaction is none
Savepoint BeforeRelease. Transaction is 9007.23.7243
Releasing lock. Transaction is 9007.23.7243
Releasing lock. Transaction is 9007.23.7243
begin
*
ERROR at line 1:
ORA-20000: dbms_lock.release returned 4 - don`t own

H: 此处一个事务被显式启动。然后BEFORE STATEMENT 触发器获取了锁,但是INSERT失败,导致语句被回滚。任何INSERT期间造成的修改都被回滚,但是既然事务还没有结束,用户锁就没有被释放。所以第二个锁请求报错:

Before insert. Transaction is 9006.15.7050
Requesting lock. Transaction is 9006.15.7050
ORA-01400: cannot insert NULL into ("ELIC"."QZ_TAB"."I")
Requesting lock. Transaction is 9006.15.7050
begin
*
ERROR at line 1:
ORA-20000: dbms_lock.request returned 4 - already own

I: 现在,事务没有被显式启动。所以INSERT隐式地创建了事务。rollback语句回滚了insert期间所做的所有修改,并且取消了隐式创建的事务。这又释放了用户锁。所以第二个锁请求成功了:

Before insert. Transaction is none
Requesting lock. Transaction is 9010.11.7136
ORA-01400: cannot insert NULL into ("ELIC"."QZ_TAB"."I")
Requesting lock. Transaction is none

PL/SQL procedure successfully completed.

J: 和选项H相反,这个选项是释放锁而不是请求锁。所以它成功了。
K: 和选项I相反,这个选项是释放锁而不是请求锁。所以它报错了 "4 - don`t own".
L: 它试图在另一个事务中获取同样的锁,所以报错了:
ORA-20000: dbms_lock.request returned 1 - timeout
M: 它试图释放一个在另一个事务中获得的锁,所以报错了:
ORA-20000: dbms_lock.release returned 4 - don`t own
N: 一个非事务性的锁可以在同一个会话的不同事务中共享。所以在子事务中释放一个从主事务中获得的会话级的锁就成功了。

使用道具 举报

回复
认证徽章
论坛徽章:
0
发表于 2018-4-10 09:34 | 显示全部楼层
楼主早,

使用道具 举报

回复
论坛徽章:
11
懒羊羊
日期:2018-02-27 22:52:20秀才
日期:2018-05-22 15:17:21技术图书徽章
日期:2018-05-22 15:17:21秀才
日期:2018-05-22 15:16:47举人
日期:2018-03-01 10:25:45秀才
日期:2018-03-01 10:21:25秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:13:04秀才
日期:2018-03-01 10:05:18
发表于 2018-4-10 09:36 | 显示全部楼层
却早已分离 发表于 2018-4-9 10:11
没有特别的意思 你可以把它当成下划线

0谢谢

使用道具 举报

回复
求职 : 数据库开发
认证徽章
论坛徽章:
4
林肯
日期:2013-07-30 18:00:55奔驰
日期:2013-08-04 16:30:37奥迪
日期:2013-08-12 12:28:15阿斯顿马丁
日期:2014-01-09 18:07:50
发表于 2018-4-10 09:55 | 显示全部楼层
(C)
begin
  qz_Lock.Request;
  qz_Lock.Request(p_ReleaseOnCommit=>false);
  qz_Lock.Release;
end;
/
C选项我改成了
  1. begin
  2. qz_Lock.Request(p_ReleaseOnCommit=>false);
  3. qz_Lock.Request;
  4. qz_Lock.Release;
  5. end;
  6. /
复制代码
也报错了,感觉本质的问题应该是不能重复申请锁

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则

TOP技术积分榜 社区积分榜 徽章 电子杂志 团队 统计 虎吧 老博客 知识索引树 读书频道 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档 | IT博客
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛 | SAP ERP系统
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 网站律师 隐私政策 知识产权声明
京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表