代码改变世界

Oracle事务之一:锁和隔离

2016-08-04 12:13  假面Wilson  阅读(553)  评论(0编辑  收藏  举报

   一. 事务概述

      事务管理是数据库处理的核心。数据库既要保证用户能并发地执行事务,还要保证数据库的一致性。

      当第一条可执行的SQL开始执行,就隐形地开始了一个事务,直到遇到下面的几种情况:

      1.Commit:提交事务。

      2.RollBack:回滚。

      3.DDL语句:执行和提交DDL语句结果前首先提交当前所有DML语句,成为隐式提交。

      4.程序正常退出:自动提交。

      5.不正常的程序失败:隐式回滚。

 

二.事务特性

      事务的四个特性:A(原子性)、C(一致性)、I(隔离性)、D(永久性)。

 

三.事务隔离级别

      数据库并发的事务会带来以下四个问题:脏读,更新丢失,不可重复读,幻读。

      对于上面这四个问题,可以通过设置不同的隔离级别来避免。

      首先是未提交读。这种并发性最高,但是仍会产生以上四个问题。

      第二种是已提交读。这是Oracle的默认隔离级别,查询语句只能看到已提交的数据。隔离的已提交读能保证在访问特定的行时,该行的数据保持不变。所以,这个级别可以防止脏读和更新丢失。

      第三种是可重复读。保证读一致性。

      最后一种是串行。隔离级别最高,但数据库的并发性受到了很大的限制。对DML操作的数据会放置一个写锁,别的涉及DML的操作不得不等待锁解除。可以避免上面的四个问题,但在现实中不可用。

 

四.多版本读一致性

    Oracle通过提供多版本来保证一致性,这个是通过撤销段来实现的。

      Oracle默认提供语句级读一致性,也就是说,查询只能看到它开始前已提交的数据,看不到执行过程中提交的数据。

    事务级读一致性就是可以保证在一个事务中的所有查询一致性。在这种情况下,每个事务中的语句都从同一个时间点来看数据,这个时间点就是事务开始时。它可以避免出现不可重复读和幻读。

 

五.锁的类型

      根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构。

      DML锁的目的在于保证并发情况下的数据完整性,在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。

      当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X 等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。

      在数据行上只有X锁(排他锁)。在 Oracle数据库中,当一个事务首次发起一个DML语句时就获得一个TX锁,该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行 DML语句时,第一个会话在该条记录上加锁,其他的会话处于等待状态。当第一个会话提交后,TX锁被释放,其他会话才可以加锁。

      下面是各种锁。

行级排他锁(Row Exclusive,简称RX锁)

      当我们进行DML时会自动在被更新的表上添加RX锁,或者也可以通过执行lock命令显式的在表上添加RX锁。在该锁定模式下,允许其他的事务通过DML语句修改相同表里的其他数据行,或通过lock命令对相同表添加RX锁定,但是不允许其他事务对相同的表添加排他锁(X锁)。

行级共享锁(Row Shared,简称RS锁)

     通常是通过select … from for update语句添加的,同时该方法也是我们用来手工锁定某些记录的主要方法。比如,当我们在查询某些记录的过程中,不希望其他用户对查询的记录进行更新操作,则可以发出这样的语句。当数据使用完毕以后,直接发出rollback命令将锁定解除。当表上添加了RS锁定以后,不允许其他事务对相同的表添加排他锁,但是允许其他的事务通过DML语句或lock命令锁定相同表里的其他数据行。

共享锁(Share,简称S锁)

     通过lock table in share mode命令添加该S锁。在该锁定模式下,不允许任何用户更新表。但是允许其他用户发出select …from for update命令对表添加RS锁。

排他锁(Exclusive,简称X锁)

     通过lock table in exclusive mode命令添加X锁。在该锁定模式下,其他用户不能对表进行任何的DML和DDL操作,该表上只能进行查询。

共享行级排他锁(Share Row Exclusive,简称SRX锁)

     通过lock table in share row exclusive mode命令添加SRX锁。该锁定模式比行级排他锁和共享锁的级别都要高,这时不能对相同的表进行DML操作,也不能添加共享锁。

     这五种模式的TM锁的兼容关系如下表所示(√表示互相兼容的请求;×表示互相不兼容的请求;N/A表示没有锁定请求):

 

-

S

X

RS

RX

SRX

N/A

S

×

×

×

X

×

×

×

×

×

RS

×

RX

×

×

×

SRX

×

×

×

×

N/A

 

      从前面的描述中可以看到,我们不仅可以通过发出DML语句的方式,由Oracle自动在表级别上添加TM锁。我们还可以通过发出lock table命令主动地在表级别上添加TM锁,并在该命令中可以指定不同的锁定模式,其命令格式如下所示:

lock table in [row share][row exclusive]

[share][share row exclusive][exclusive] mode;

      对Oracle数据库中的各SQL语句所产生的表级锁的情况进行汇总,如下表所示:

 

SQL语句

表锁定模

允许的表锁定模式

Select * from ……

RS

RS、RX、S、SRX、X

Insert into ……

RX

RS、RX

Update ……

RX

RS、RX

Delete from ……

RX

RS、RX

Select * from for update

RS

RS、RX、S、SRX

lock table in row share mode

RS

RS、RX、S、SRX

lock table in row exclusive mode

RX

RS、RX

lock table in share mode

S

RS、S

lock table in share row exclusive mode

SRX

RS

lock table in exclusive mode

X

RS

 

    对于通过lock table命令主动添加的锁定来说,如果要释放它们,只需要发出rollback命令即可。

 

 六.我学习中的疑惑和解答

疑惑:既然已经有了锁,为什么还要有隔离级别?

解答:在csdn上找到一个答案,地址:http://topic.csdn.net/u/20100713/12/7e6e102e-03f9-420e-81b3-527ab4437792.html

具体:

事务隔离级别是并发控制的整体解决方案,其实际上是综合利用各种类型的锁和行版本控制,来解决并发问题。
锁是数据库并发控制的内部机制,是基础。当然,数据库同时还会利用行版本控制(SQL Server 2005 及以上)来进行并发控制;在数据库内部还使用闩(latch),互斥(mutex)等机制处理内部资源(如,缓存)的并发访问。
对用户来说,只有当事务隔离级别无法解决一些并发问题和需求时,才有必要在语句中手动设置锁。不适当的设置锁,可能会导致严重的阻塞和死锁。建议,只有在完全了解锁机制的情况下,才可以在语句中手动设置锁,否则应该使用事务隔离级别。