设为首页 收藏本站
查看: 1099|回复: 0

[经验分享] oracle Select For update语句浅析

[复制链接]

尚未签到

发表于 2018-9-22 12:58:31 | 显示全部楼层 |阅读模式
  Select …forupdate语句是我们经常使用手工加锁语句。通常情况下,select语句是不会对数据加锁,妨碍影响其他的DML和DDL操作。同时,在多版本一致读机制的支持下,select语句也不会被其他类型语句所阻碍。
  借助for update子句,我们可以在应用程序的层面手工实现数据加锁保护操作。本篇我们就来介绍一下这个子句的用法和功能。
  下面是采自Oracle官方文档《SQLLanguage Reference》中关于for update子句的说明:(请双击点开图片查看)

  从for update子句的语法状态图中,我们可以看出该子句分为两个部分:加锁范围子句和加锁行为子句。下面我们分别针对两个方面的进行介绍。
  加锁范围子句
  在select…for update之后,可以使用of子句选择对select的特定数据表进行加锁操作。默认情况下,不使用of子句表示在select所有的数据表中加锁。
  //采用默认格式for update
  SQL> select * from emp where rownum select addr,xidusn,xidslot,xidsqn from v$transaction;
  ADDR        XIDUSN   XIDSLOT    XIDSQN
  -------- ---------- ---------- ----------
  377DB5D0         7        19       808
  //锁对象信息
  SQL> select xidusn,xidslot,xidsqn,object_id,session_id, oracle_username from v$locked_object;
  XIDUSN   XIDSLOT    XIDSQN OBJECT_ID SESSION_ID ORACLE_USERNAME
  ---------- ---------- ---------- ---------- ---------- ------------------------------
  7        19       808     73181        36 SCOTT
  //
  SQL> select owner,object_name from dba_objects where object_id=73181;
  OWNER                         OBJECT_NAME
  ------------------------------ ------------------------------------------------------------
  SCOTT                         EMP
  //

  SQL> select addr, sid, type,>  ADDR     SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK
  -------- ---------- ---- ---------- ---------- ---------- ---------- ----------
  37E808F0   36 AE         100         0         4         0   0
  B7DE8A44  36 TM       73181         0         3         0  0
  377DB5D0  36 TX      458771       808         6         0   0
  从上面的情况看,默认情况下的for update语句,效果相当于启动了一个会话级别的事务,在对应的数据表(select所涉及的所有数据表)上加入一个数据表级共享锁(TM,lmode=3)。同时,在对应的数据行中加入独占锁(TX,lmode=6)。
  根据我们以前的知识,如果此时有另一个会话视图获取对应数据行的独占权限(无论是用update/delete还是另一个for update),都会以block而告终。
  SQL> select sid from v$mystat where rownum select * from emp where empno=7369 for update;
  //系统blocking
  此时系统中状态,切换到另一个用户下进行观察:

  SQL> select addr, sid, type,>  ADDR  SID TYPE       ID1       ID2     LMODE   REQUEST     BLOCK
  -------- ---------- ---- ---------- ---------- ---------- ---------- ----------
  37E808F0        36 AE         100         0         4         0  0
  37E80ED4        37 AE         100         0         4         0  0
  37E80F48        37 TX      458771       808         0         6  0
  B7DE8A44        37 TM       73181         0         3         0 0
  B7DE8A44        36 TM       73181         0         3         0 0
  377DB5D0        36 TX      458771       808         6         0 1
  6 rows selected
  SQL> select * from dba_waiters;
  WAITING_SESSION HOLDING_SESSION LOCK_TYPE                 MODE_HELD                               MODE_REQUESTED                            LOCK_ID1  LOCK_ID2
  --------------- --------------- -------------------------- ---------------------------------------- ---------------------------------------- ---------- ----------
  37             36Transaction               Exclusive                               Exclusive                                   458771       808
  由此,我们可以获取到结论:for update子句的默认行为就是自动启动一个事务,借助事务的锁机制将数据进行锁定。
  Of子句是配合for update语句使用的一个范围说明标记。从官方的语法结构看,后面可以跟一个或者多个数据列列表。这种语法场景常常使用在进行连接查询的select中,对其中一张数据表数据进行锁定。
  SQL> select empno,ename,job,mgr,sal from emp,dept where emp.deptno=dept.deptno and empno=7369 for update of emp.empno;
  EMPNO ENAME     JOB        MGR      SAL
  ----- ---------- --------- ----- ---------
  7369 SMITH     CLERK     7902   800.00

  SQL> select addr, sid, type,>  ADDR      SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK
  -------- ---------- ---- ---------- ---------- ---------- ---------- ----------
  37E808F0        36 AE         100         0         4         0   0
  B7E1C2E8        36 TM       73181         0         3        0   0
  377DBC0C        36 TX       65566       747         6      0  0
  上面的语句中,我们看到使用for update of指定数据列之后,锁定的范围限制在了所在的数据表。也就是说,当我们使用连接查询配合of子句的时候,可以实现有针对性的锁定。
  同样在连接查询的时候,如果没有of子句,同样采用默认的模式,会如何呢?
  SQL> select empno,ename,job,mgr,sal from emp,dept where emp.deptno=dept.deptno and empno=7369 for update;
  EMPNO ENAME     JOB        MGR      SAL
  ----- ---------- --------- ----- ---------
  7369 SMITH     CLERK     7902   800.00

  SQL> select addr, sid, type,>  ADDR    SID TYPE       ID1       ID2     LMODE   REQUEST BLOCK
  -------- ---------- ---- ---------- ---------- ---------- ---------- ----------
  37E808F0        36 AE         100         0         4         0    0
  B7E1C2E8        36 TM       73179         0         3         0  0
  B7E1C2E8        36 TM       73181         0         3         0    0
  377DBC0C        36 TX      458777       805         6         0   0
  SQL> select owner,object_name from dba_objects where object_id=73179;
  OWNER                         OBJECT_NAME
  ------------------------------ --------------------------------------------------------------------------------
  SCOTT                         DEPT
  明显可以看到,当我们没有使用of子句的时候,默认就是对所有select的数据表进行lock操作。
  加锁行为子句
  加锁行为子句相对比较容易理解。这里分别介绍。
  Nowait子句
  当我们进行for update的操作时,与普通select存在很大不同。一般select是不需要考虑数据是否被锁定,最多根据多版本一致读的特性读取之前的版本。加入for update之后,Oracle就要求启动一个新事务,尝试对数据进行加锁。如果当前已经被加锁,默认的行为必然是block等待。
  使用nowait子句的作用就是避免进行等待,当发现请求加锁资源被锁定未释放的时候,直接报错返回。
  ///session1中
  SQL> select * from emp for update;
  EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO
  ----- ---------- --------- ----- ----------- --------- --------- ------
  7369 SMITH     CLERK     79021980-12-17    800.00              20
  7499 ALLEN     SALESMAN  76981981-2-20    1600.00   300.00    30
  7521 WARD      SALESMAN  76981981-2-22    1250.00   500.00    30
  7566 JONES     MANAGER   78391981-4-2     2975.00              20
  //变换session,进行执行。
  SQL> select * from emp for update nowait;
  select * from emp for update nowait
  ORA-00054:资源正忙,但指定以NOWAIT方式获取资源,或者超时失效
  对应的还有就是wait子句,也就是默认的for update行为。一旦发现对应资源被锁定,就等待blocking,直到资源被释放或者用户强制终止命令。
  对wait子句还存在一个数据参数位,表示当出现blocking等待的时候最多等待多长时间。单位是秒级别。
  //接上面的案例
  SQL> select * from emp for update wait 3;
  select * from emp for update wait 3
  ORA-30006:资源已被占用;执行操作时出现WAIT超时
  Skip locked参数
  Skip locked参数是最新引入到for update语句中的一个参数。简单的说,就是在对数据行进行加锁操作时,如果发现数据行被锁定,就跳过处理。这样for update就只针对未加锁的数据行进行处理加锁。
  //session1中,对一部分数据加锁;
  SQL> select * from emp where rownum select * from emp for update skip locked;
  EMPNO ENAME     JOB        MGR HIREDATE         SAL     COMM DEPTNO
  ----- ---------- --------- ----- ----------- --------- --------- ------
  (篇幅原因,省略)
  7934 MILLER    CLERK     77821982-1-23    1300.00              10
  11 rows selected
  总数据一共14行。Session1中,先lock住了3行数据。之后的seesion2中,由于使用的skip locked子句参数,将剩下的11条数据进行读取到并且加锁。
  对for update的使用
  在日常中,我们对for update的使用还是比较普遍的,特别是在如pl/sql developer中手工修改数据。此时只是觉得方便,而对for update真正的含义缺乏理解。
  For update是Oracle提供的手工提高锁级别和范围的特例语句。Oracle的锁机制是目前各类型数据库锁机制中比较优秀的。所以,Oracle认为一般不需要用户和应用直接进行锁的控制和提升。甚至认为死锁这类锁相关问题的出现场景,大都与手工提升锁有关。所以,Oracle并不推荐使用for update作为日常开发使用。而且,在平时开发和运维中,使用了for update却忘记提交,会引起很多锁表故障。
  那么,什么时候需要使用for update?就是那些需要业务层面数据独占时,可以考虑使用for update。场景上,比如火车票订票,在屏幕上显示邮票,而真正进行出票时,需要重新确定一下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使用for update。这是统一的解决方案方案问题,需要前期有所准备


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-599924-1-1.html 上篇帖子: oracle10g重建oem dbconsole 下篇帖子: ORACLE的直方图的一些试验
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表