上篇介绍了数据并发与一致性的相关概念、以及oracle的事务隔离级别等内容,本篇继续介绍锁机制、自动锁、手动锁、用户自定义锁的相关内容。

  请尊重作者劳动成果,转载请标明原文链接:

  https://www.cnblogs.com/jpcflyer/p/9169357.html

一、锁机制

事务之间的并发控制实际是通过锁实现的,锁是用来预防事务之间访问相同数据时的破坏性交互(比如错误的更新数据等)的一种机制,在维护数据库并发性与一致性方面扮演了一个重要角色。

1.锁的基本概念

一般来说,数据库有两种类型的锁:共享锁(share locks)和排他锁(exclusive locks)。一个资源(比如一行或一个表)上面只能有一个排他锁,但可以有多个共享锁。具体后文会有详细介绍。锁会影响到查询reader和writer的交互(reader是查询某资源,writer是修改某资源),下面总结了Oracle中reader和writer的锁定行为:

  • 只有一个writer 在修改一行时,这一行才会被锁:当一个语句更新了一行,则事务只获取了这一行的锁,以实现数据库的最小争用。在正常情况下,数据库不会将行锁升级为块锁,甚至表锁。
  • 某行的writer会阻塞并发的该行的其它writer:如果一个事务在修改某一行,那么行锁会阻止其它事务在这一时间内修改这一行
  • reader永远不会堵塞writer:因为该行的reader不会对这行上锁(当然select .. for update除外,这是个特殊的select)
  • writer永远不会堵塞reader:当一个writer正在修改一行时,数据库通过使用undo数据来对reader提供读一致性(上篇有过介绍了)

注意:在一些非常特殊的场景中,reader可能会等待同一个块的写。

2.锁的使用

数据库使用锁完成了下面的重要需求:

  • 一致性(Consistency):正在查看或修改的数据不能被其它session修改,直到用户修改完成
  • 完整性(Integrity):数据或结构必须按正确的顺序来反应对它们所做的所有修改

锁是根据需要自动执行的,不需要用户做什么操作。看下面的一个简单案例:

1 UPDATE employees
2 SET    email = ?, phone_number = ?
3 WHERE  employee_id = ?
4 AND    email = ?
5 AND    phone_number = ?

在此update中,email和phone_number都是原始的值,这样更新,能够避免上篇提到的丢失更新的问题。下表显示了当两个会话在相同时间更新employees表中相同的行时的执行顺序:

时间 会议1 会议2 说明

t0

SELECT employee_id, email, phone_number
FROM   hr.employees
WHERE  last_name = 'Himuro';EMPLOYEE_ID EMAIL   PHONE_NUMBER
----------- ------- ------------118 GHIMURO 515.127.4565
 

t1

 
SELECT employee_id, email, phone_number
FROM   hr.employees
WHERE  last_name = 'Himuro';EMPLOYEE_ID EMAIL   PHONE_NUMBER
----------- ------- ------------118 GHIMURO 515.127.4565

t2

UPDATE hr.employees
SET phone_number='515.555.1234'
WHERE employee_id=118
AND email='GHIMURO'
AND phone_number='515.127.4565';1 row updated.
 

会话1获得了修改行的行锁

t3

 
UPDATE hr.employees
SET phone_number='515.555.1235'
WHERE employee_id=118
AND email='GHIMURO'
AND phone_number='515.127.4565';-- SQL*Plus does not show
-- a row updated message or
-- return the prompt.

会话2尝试获取相同行的行锁,但发生了阻塞

t4

COMMIT;Commit complete.
 

会话1提交

t5

 
0 rows updated.

因为where条件不匹配,所以会话2没有更新任何记录

t6

UPDATE hr.employees
SET phone_number='515.555.1235'
WHERE employee_id=118
AND email='GHIMURO'
AND phone_number='515.555.1234';1 row updated.
 

t7

 
SELECT employee_id, email, phone_number
FROM   hr.employees
WHERE  last_name = 'Himuro';EMPLOYEE_ID EMAIL   PHONE_NUMBER
----------- ------- ------------118 GHIMURO 515.555.1234

oracle的读一致性使得会话2看不到未提交的t6的修改

t8

 
UPDATE hr.employees
SET phone_number='515.555.1235'
WHERE employee_id=118
AND email='GHIMURO'
AND phone_number='515.555.1234';-- SQL*Plus does not show
-- a row updated message or
-- return the prompt.

t9

ROLLBACK;Rollback complete.
 

t10

 
1 row updated.

会话2中发现一行匹配的记录

t11

 
COMMIT;Commit complete.

Oracle数据库在执行sql的时候会自动获取所需要的锁,因此用户在应用设计的时候只需要定义恰当的事务级别,不需要显示锁定任何资源。(即使oracle提供了手动锁定数据的方法,用户不会用到。)

3.锁模式

Oracle自动使用最低的限制级别去提供最高程度的并发。Oracle中有两种类型的锁:

  • 排他锁(exclusive lock):这种类型是阻止资源共享的,一个事务获取了一个排他锁,则这个事务锁定期间只有这个事务可以修改这个资源
  • 共享锁(share lock):这种类型是允许资源共享的,多个事务可以在同一资源上获取共享锁

假设一个事务使用select ... for update(其它DML操作也一样)来选择表中的一行,则这个事务会获取该行的排他行锁,以及所在表的共享表锁。行锁允许其它事务修改除该行的其它行,而表锁阻止其它事务修改表结构。

4.锁转换和锁升级

Oracle在需要的时候会自动执行锁转换,在转换过程中,会将低限制的锁转换为高限制的锁。举例来说,当一个事务执行select ... for update查出一行,之后更新该行,在这种场景下,Oracle会自动将 共享表 锁转换为 行独占表锁。其它的DML操作也会持有一样的锁。此时,获取的行锁已经在最高限制级别了,所以不会在执行锁转换了。

锁转换和锁升级不一样,锁升级发生在当某个粒度级别持有很多锁时,数据库会将锁升级到更高的粒度级别。比如一个用户锁了一个表中的很多行,那么很多数据库会自动将锁升级为表锁,这样锁的数据就减少了,但限制程度也增加了。

Oracle永远不会执行锁升级。锁升级极大的增加了死锁的可能性。想想为什么?因为事务1执行过程中需要升级锁,但因为被事务2锁住了相关资源而不能升级,而事务2此时也在等待事务1已锁住的资源,这样就死锁了。

5.锁持续时间

当事务结束(执行commit或rollback)时,锁会被释放。注意,当执行rollback时,是先回滚到savepoint后,才释放锁。

6.死锁

Oracle会自动检测死锁,并通过回滚其中一个语句来解决死锁。当然,可以在等待一段时间后,重试被回滚的语句。下面描述了一个死锁的场景:

时间 会话1 会话2 说明

t0

SQL> UPDATE employees SET salary = salary*1.1WHERE employee_id = 100;1 row updated.
SQL> UPDATE employeesSET  salary = salary*1.1WHERE employee_id = 200;1 row updated.

t1

SQL> UPDATE employees SET salary = salary*1.1WHERE employee_id = 200;-- prompt does not return
SQL> UPDATE employeessalary = salary*1.1WHERE employee_id = 100;-- prompt does not return

发生了死锁

t2

UPDATE employees*
ERROR at line 1:
ORA-00060: deadlock detected
while waiting for resourceSQL>
 

事务1发生死锁信息并回滚

t3

SQL> COMMIT;Commit complete.
 

t4

 
1 row updated.SQL>

t5

 
SQL> COMMIT;Commit complete.

二、自动锁

Oracle的锁可以分为以下几个类别:

  • DML锁:保护数据,比如表锁是锁定整个表,而行锁是锁定指定行
  • DDL锁:保护对象的结构,比如表和视图的定义
  • 系统锁:保护内部的数据库结构,比如数据文件,latch, mutexes以及内部锁

1.DML锁

DML锁可以防止多个互相冲突的DDL,DML操作对数据的破坏性。DML语句自动获取两种类型的锁:Row locks(TX)和Table locks(TM)。(这个简写是oracle EM的locks monitor中使用的缩略语)。

1)行锁(Row locks或TX)

事务通过insert, update, delete, merge或select ... for update修改的任何行都会加上行锁,行锁只有排他模式,行锁会持续到事务结束(commit或rollback)。

注意:如果一个事务因为数据库异常关闭,会先进行块级恢复以使行可用,然后再进行整个事务的恢复。

如果一个事务获取了一行的行锁,那么也同样获取了所在表的表锁,表锁的作用是阻止冲突性地DDL操作。下面描述了更新表中的一行数据,即自动锁了行,又自动锁了表:

下表解释了Oracle通过锁实现并发性。三个会话同时查询相同的行,会话1和会话2分别更新了不同行,但没有提交,而会话3没有做任何更新。每个会话都能看到它自己做的未提交更新,但不能看到其它会话的未提交更新。

Time Session 1 Session 2 Session 3

t0

SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600
SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600
SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600

t1

UPDATE hr.employees
SET salary=salary+100
WHERE employee_id=100;
   

t2

SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          612
101          600
SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600
SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600

t3

 
UPDATE hr.employees
SET salary=salary+100
WHERE employee_id=101;
 

t4

SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          612
101          600
SELECT employee_id,
salaryFROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          700
SELECT employee_id,
salary FROM employees
WHERE  employee_id
IN ( 100, 101 );EMPLOYEE_ID  SALARY
-----------  ------
100          512
101          600

2)表锁(Table locks或TM)

当事务通过insert, update, delete, merge, select ... for update修改数据时,或者直接用Lock table语句时,会对表加上TM锁。表锁有以下几种模式:

  • Row share lock(RS, 行共享表锁)

也叫subshare table lock(SS),表明事务在这个表上锁住了一行,并且打算更新它们,RS锁是最小约束的锁,当然也是并发最高的锁

  • Row Exclusive Table lock(RX,行排他表锁)

也叫subexclusive table lock(SX),表明表中有事务更新了行,或者执行select ... for update。一个SX锁允许其它事务同时查询、插入、更新、删除或者锁行。因此多个事务可以同时获取在同一个表上获取SS和SX锁。

  • Share Table lock(S,共享表锁)

一个事务持有了S锁,允许其它事务查询这个表(除了select ... for udpate),但更新操作只允许单个事务持有该锁时才可以。因为多个事务可能会并发持有这个锁,所以持有了这个锁并不代表这个事务就可以修改表。

  • Share Row Exclusive Table lock(SRX, 共享行排他表锁)

也叫share-subexclusive table lock(SSX),比S锁的限制更多,一次只能有一个事务获取SSX锁,允许其它事务查询(除了select ... for update),不允许其它事务更新。

  • Exclusive Table lock(X, 排他表锁)

是最大限制的锁,禁止其它事务执行任何DML语句或设置任何类型的锁到这个表。

2.DDL锁

当事务执行DDL操作需要DDL锁时,Oracle会自动获取,不需要显示获取。举例来说,如果用户正在创建一个存储过程,那么Oracle会自动获取这个存储过程所有引用到的schema objects上的DDL。这些DDL锁是为了防止在存储过程还没编译完成时,相关的对象就被删除或者修改结构了。

  • Exclusive DDL locks(排他DDL锁)

排他DDL锁,阻止其它会话获取DDL或DML锁。举例来说,DROP TABLE命令在执行是不允许ALTER TABLE的,反之亦然。

  • Share DDL locks(共享DDL锁)

共享DDL锁用于阻止与它冲突的DDL操作,但允许相似的DDL操作并发执行。举例来说,当执行CREATE PROCEDURE时,会获取到所有引用表的的共享DDL锁,其它事务也可以在相应的表上并发的CREATE PROCEDURE获取共享DDL锁,但不允许在被引用的表上获取DDL锁。

3.系统锁

Oracle也提供了多种类型的系统锁来保护数据库和内存的内部结构,由于用户无法控制它们何时出现和持续多久,所以这些机制对用户来说几乎是不可见的。

  • Latch(闩锁)

Latch是低级别的串行化机制,它协调多个用户访问这些共享的数据结构、对象、文件。当多个进程读取一个共享内存资源时使用Latch保护其不受损坏。具体来说,Latch在以下情况保护数据结构:多个会话的并发修改、读取一个正在被别人修改的资源、当访问的时候,内存被释放。V$LATCH事务包含了每个latch的使用状态的详细信息,包括latch被请求和被等待的次数。

  • Mutexes(互斥器)

Mutex是Mutual exclusion object(互相排斥对象)的缩写,是低级别的锁,防止内存中的对象被并行访问时被换出或被损坏。Mutex和Latch很相似,但是一个Latch基本上保护一级object,而mutex保护单个object。

  • Internal Locks(内部锁)

内部锁是高级别的锁,比latch和mutex要复杂的多,用于各种场景。Oracle有以下几种类型的内部锁:字典缓存锁、文件和日志管理锁、表空间和undo段锁。这里就不详细介绍了。

三、手动锁

Oracle除了保用自动锁外,还可以使用手动锁覆盖默认的锁机制。举例来说,事务中包含如下语句时会覆盖Oracle的默认锁:SET TRANSACTION ISOLATION LEVEL, LOCK TABLE, SELECT ... FOR UPDATE。

四、用户自定义锁

可以通过DBMS_LOCK包调用锁管理服务,包含功能有请求指定类型的锁、给锁一个唯一名字、修改锁类型、锁释放等等。

到此为止,Oracle中的数据并发与一致性就介绍完了,限于精力,有些没有展开介绍,各位感兴趣的话可以发邮件一起交流。

转载于:https://www.cnblogs.com/jpcflyer/p/9169357.html

Oracle的数据并发与一致性详解(下)相关推荐

  1. oracle 误删除表数据,Oracle误删除表数据后的数据恢复详解

    Oracle误删除表数据后的恢复详解 测试环境: SYSTEM:IBM AIX 5L                         Oracle Version:10gR2 1. undo_rete ...

  2. oracle中imp命令详解,ORACLE EXPDP IMPDP数据导入导出命令详解及同EXP IMP命令详细对照...

    ORACLE EXPDP IMPDP数据导入导出命令详解及同EXP IMP 命令详细对比 一.EXPDP IMPDP EXP IMP 可以实现 1.可以实现逻辑备份和逻辑恢复 2.可以在数据库用户之间 ...

  3. Oracle中序列(Sequence)详解

    Oracle中序列(Sequence)详解 一 序列定义 序列(SEQUENCE)是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值(类型为数字).不占用磁盘空间,占用内存. 其主要用 ...

  4. oracle imp 1403,Oracle中用exp/imp命令参数详解【转】

    Oracle中用exp/imp命令参数详解 [用 exp 数 据 导 出]: 1  将数据库TEST完全导出,用户名system 密码manager 导出到D:daochu.dmp中 expsyste ...

  5. Oracle中游标Cursor基本用法详解

    这篇文章主要介绍了Oracle中游标Cursor基本用法详解,还是比较全面的,具有一定参考价值,需要的朋友可以了解下. 查询 SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT ...

  6. 千万级PV规模高性能高并发网站架构详解

    1.缓存(expires) 2.deflate压缩 3.Apache/nginx静态服务器提供html页面内容 4.CDN/cache缓存静态内容如:html.jpg.gif.js等 5.MYSQL数 ...

  7. 创建emp表 oracle,Oracle中创建和管理表详解

    Oracle中创建和管理表详解 更新时间:2013年08月01日 15:44:16   作者: 以下是对Oracle中的创建和管理表进行了详细的分析介绍,需要的朋友可以过来参考下 SQL> /* ...

  8. 在oracle中游标的操作,Oracle中的游标和函数详解

    Oracle中的游标和函数详解 1.游标 游标是一种 PL/SQL 控制结构:可以对 SQL 语句的处理进行显示控制,便于对表的行数据 逐条进行处理. 游标并不是一个数据库对象,只是存留在内存中. 操 ...

  9. oracle通过dblink连接mysql配置详解(全Windows下)

    oracle通过dblink连接mysql配置详解(全Windows下) 关于oracle通过dblink连接mysql,经过了两周的空闲时间研究学习,终于配置好了,真是不容易啊,仔细想想的话,其实也 ...

最新文章

  1. 两波形相位差的计算值_正弦交流电的相位差,明白了吗?
  2. java调用存储过程之环境测试
  3. 《数据库SQL实战》查找所有员工的last_name和first_name以及对应的dept_name
  4. Optimizing Code with GCC
  5. python pandas csv getitem_Python调用pandas 读csv档时出现了错误
  6. jq之$(“*“)隐藏所有元素
  7. java接口如何接受语音参数_Java 是如何优雅地实现接口数据校验的?
  8. 复杂性思维第二版 四、无标度网络
  9. 整数不少于12可以表示为两个复合数字的和
  10. NSCT(Nonsubsampled Contourlet变换)
  11. 1196971406
  12. 无锁循环缓冲区的实现c语言,C++ 无锁环形缓冲区实现
  13. 电子设计推荐看的好书
  14. 软件测试的艺术读书笔记
  15. 乐max2 android9,辣评烩:乐Max 2即将升级EUI 6.0 基于安卓7.0!
  16. Java进阶之计算机组成原理概述
  17. PAT基础级-黄金段位样卷1
  18. java hbase连接kerberos的几个常见错误
  19. 搭建企业内外网可快速稳定访问的共享文件服务器方案
  20. 京东抢购Python脚本

热门文章

  1. 已解决:An error occurred at line: 1 in the generated java file The type java.io.ObjectInputStream canno
  2. 商标注册流程与注意事项
  3. 在pytorch中使用tensorboard
  4. bagging和时间序列预测_Simple RNN时间序列预测
  5. iframe重新加载与修改提交不关闭窗口属性页面
  6. npm ERR! code ERR_STREAM_WRITE_AFTER_END npm install 报错实力踩坑npm,自从用了npm之后项目构建和插件管理确实方便了很多,但也是被坑的不要不要的
  7. 九大内置对象及四个域对象的总结
  8. php遍历指定目录下的文件,PHP遍历指定目录下所有文件和目录
  9. python import system_[Python Basics]引用系统(The Import System)
  10. java jvm bind解决_java web项目启动的时候JVM_Bind,真的是tomcat端口被占用了吗?tomcat不同意...