SQL SERVER技术内幕之10 事务并发

1.事务

1.1事务的定义

事务是作为单个工作单元而执行的一系列操作。定义事务边界有显式和隐式两种。显式事务的定义以BEGIN TRAN作为开始,以COMMIT TRAN提交事务,以ROLLBACK TRAN撤销事务。如果不显式定义事务的边界,SQL Server会默认把每个单独的语句作为一个事务。也就是说,SQL Server默认在执行完每个语句之后就自动提交事务。可以通过IMPLICIT_TRANSACTIONS会话选项来改变SQL Server处理隐式事务的方式。

1.2事务的属性

(1)原子性:事务必须是原子工作单元,这意味着在事务中进行的修改,要么全都执行,要么全都不执行。
(2)一致性:同时发生的事务在修改和查询数据时不发生冲突,通过RDBMS访问的数据要保持一致的状态。
(3)隔离性:隔离性是一种用于控制数据访问的机制,能够确保事务只访问处于期望的一致性级别下的数据。
(4)持久性:在将数据修改写入到磁盘上数据库的数据分区之前,总是先把这些修改写入到磁盘上数据库的事务日志中。

2.锁定和阻塞

2.1锁

锁是事务获取的一种控制资源,用于保护数据资源,防止其他事务对数据进行冲突的或不兼容的访问。
(1)锁模式及其兼容性
排他锁:对于相同的数据类型,如果有其他事务已经获得了该资源其他类型的锁,就不能再获得该资源的排他锁。如果有其他事务已经获得了该资源的排他锁,就不能再获得该资源的任何类型的锁。当试图修改数据时,事务会为所依赖的数据资源请求排他锁。这是修改行为的默认处理方式,而且这种默认行为不能改变,不能改变为修改数据资源而请求的锁模式(排他锁),也不能改变持有锁的时间长度(直到事务完成)
共享锁:多个事务可以同时持有同一数据资源上的共享锁。当试图读取数据时,事务默认会为所依赖的数据资源请求共享锁。读取操作一旦完成,就即释放资源上的共享锁,虽然当修改数据时不能改变请求的锁模式和持续时间,但当读取数据时可以对如何处理锁定进行控制。
SQL SERVER技术内幕之10 事务并发

(2)可锁定资源的类型
SQL Server可以锁定不同类型或粒度的资源,这些资源类型包括行、页、对象(例如表)、数据库等。行位于页中,而页则是包含表或索引数据的物理数据块。为了获得特定资源类型上的锁,事务必须先在更高的粒度级别上获得相同模式的意向锁,例如,为了获得某一行的排他锁,事务必须先在包含那一行的页上获取意向排他锁。同样,要获得某一粒度级别上的共享锁,事务就必须先在更高的粒度级别上获取意向共享锁。意向锁的目的是为了在较高的粒度级别上有效地检测不兼容的锁定请求,防止授予不兼容的锁。例如一个事务持有一个行锁,而其他事务想在包含那一行的整个页或表上请求不兼容的锁模式,这时SQL Server可以很容易地识别出这种冲突。意向锁不会干预较低粒度上的锁定请求,一个页上的意向锁不会阻止其他事务在该页内的行上获取不兼容的锁模式。
SQL SERVER技术内幕之10 事务并发
SQL Server动态决定应该锁定哪种类型的资源。自然,为了获得理想的并发性,最好是只锁定需要的资源,即只锁定受影响的行。但是,锁定需要占用内存资源和内部的管理开销,所以SQL Server在选择锁定哪种类型的资源时会同时考虑并发性和系统资源。SQL Server会先获得细粒度的锁(例如行或页),在某些情况下再尝试将锁升级为更粗粒度的锁例(如表)。例如当单个语句获得至少5,000个锁时,就会触发锁升级。

3.隔离级别
隔离级别用于决定如何控制并发用户读写数据的操作。对于操作获得的锁以及锁的持续时间来说,虽然不能控制写操作的处理方式,但可以控制读操作的处理方式。当然,作为 对读操作的行为进行控制的一种结果,也将隐含地影响写操作的处理方式。可以在会话级别或查询级别来设置隔离级别。
要设置整个会话的隔离级别,可以使用以下命令:
SET TRANSACTION ISOLATION LEVEL <isolation name>;
要可以使用表提示来设置查询的隔离级别:
SELECT … FROM <table> WITH (<isolationname>)
默认的隔离级别是READ COMMITTED。如果你选择修改这个默认的级别,那么选择的结果对数据库用户的并发性和他们获取数据的一致性都会产生影响。对于SQL Server 2005之前可用的四个隔离级别(如下所示的前4个隔离级别),隔离级别越高,读操作请求的锁定就越严格,锁持有的时间也就更长,因此,隔离级别越高,一致性也就越高,并发性也就越低。
(1)READ UNCOMMITTED 未提交读
在这个隔离级别运行的事务,读操作不会请求共享锁。这意味着读操作可以读取未提交的修改(脏读)
(2)READ COMMITTED(默认) 已提交读
如果想避免读取未提交的修改,则需要使用要求更严格的隔离级别。能够防止脏读的最低隔离级别是READ COMMITTED,这也是所有版本的SQL Server默认使用的隔离级别。这个隔离级别只允许读取已经提交过的修改。它要求读操作必须获得共享锁才能进行操作,从而防止读取未提交的修改。
按照锁的持有时间来说,在READ COMMITTED隔离级别中,读操作一完成,就立即释放资源上的共享锁,这意味着在一个事务处理内部对相同数据资源的两个读操作之间,没有共享锁会锁定该资源,其他事务可以在两个读操作之间更改数据资源,读操作因而可能每次得到不同的取值。这种现象称为不可重复读或不一致的分析。
(3)REPEATABLE READ 可重复读
如果想保证在事务内进行的两个读操作之间,其他任何事务都不能修改由当前事务读取的数据,则需要把隔离级别升级为REPEATABLE READ.在这种隔离级别下,事务中的读操作不但需要获得共享锁才能读取数据,而且获得的共享锁将一直保持到事务完成为止。
REPEATABLE READ隔离级别能够防止的另一种并发负面影响是丢失更新,而较低的隔离级别则不能防止这种问题。因为在比REPEATABLE READ更低的隔离级别中,读取完数据之后就不再持有资源上的任何锁,两个事务都能更新这个值,而最后进行更新的事务则是”赢家”,覆盖由其他事务所作的更新,这将导致数据丢失。
(4)SERIALIZABLE可序列化
在REPEATABLE READ隔离级别是运行的事务,读操作获得的共享锁将一直保持到事务完成为止。因此可以保证在事务中第一次读取某些行后,还可以重复读取这些行。但是,事务只锁定查询第一次运行时找到的那些数据资源,而不会锁定查询结果范围以外的其他行。因此,在同一事务中进行第二次读取之前,如果其他事务插入了新行,而且新行也能满足读操作的查询过滤条件,那么这些新行也会出现在第二次读操作返回的结果中,这些新行称为幻影。
SERIABLIZABLE与REPEATABLE READ类似:却读操作需要获得共享锁才能读取数据,并保留共享锁直到事务完成。不过,SERIALIZABLE隔离级别增加了一个新内容:逻辑上,这就意味着读操作不仅锁定了满足查询搜索条件的现有的那些行,还锁定了未来可能满足查询搜索条件的行。

4.死锁
死锁是指一种进程之间互相永久阻塞的状态,可能涉及两个或更多的进程。

上一篇:SQLServer 添加序号列


下一篇:Underscore.js 源码学习笔记(下)