一. 事务概述
事务管理是数据库处理的核心。数据库既要保证用户能并发地执行事务,还要保证数据库的一致性。
当第一条可执行的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)等机制处理内部资源(如,缓存)的并发访问。
对用户来说,只有当事务隔离级别无法解决一些并发问题和需求时,才有必要在语句中手动设置锁。不适当的设置锁,可能会导致严重的阻塞和死锁。建议,只有在完全了解锁机制的情况下,才可以在语句中手动设置锁,否则应该使用事务隔离级别。