葡京网投哪个正规 > 新葡亰-数据 > 【葡京网投哪个正规】锁与事务拨云见日,事物与锁

原标题:【葡京网投哪个正规】锁与事务拨云见日,事物与锁

浏览次数:130 时间:2019-11-30

一.事务的概述

   上一章节里,重点讲到了锁,以及锁与事务的关系。离上篇发布时间好几天了,每天利用一点空闲时间还真是要坚持。听《明朝那些事儿》中讲到"人与人最小的差距是聪明,人与人最大的差距是坚持"很经典的一句话一直记得。这篇重点围绕事务来开展。涉及的知识点包括:事务的概述,事务并发控制模型,并发产生的负面影响,事务隔离级别以及不同的表现。本章多以文字描述为主,没有多少代码量,重点是阐述不同隔离级别的不同表现,在以后的业务中,涉及到事务时,本文可以用来做个参考。

1.1 事务ACID

    事务作为一个逻辑工作单元执行一系列的操作,它包括四个属性:原子性、一致性、隔离性和持久性 (ACID) 属性, 只有这样才能成为一个事务。  

    原子性:当一个事务被当作一个单独的工作单元时,不管事务内有什么,都是一个整体。对于其数据修改,要么全都执行,要么全都不执行。  

       一致性:事务在完成时,必须使所有的数据都保持一个逻辑一致状态。   

  隔离性:并发事务所做的修改必须与其他并发事务所做的修改隔离。 事务能识别数据所处的状态,要么是另一并发事务修改它之前的状态,要么是并发事务修改它之后的状态。

  持久性:一但事务完全,它的效果是永久存于系统的。该修改即使出现系统故障也将一直保持。 SQL Server 2014和更高版本启用延迟的持久事务。

1.2 事务的操作模式有几下几种:

  自动提交事务:每条单独的语句都是一个事务。

  显式事务:每个事务均以 BEGIN TRANSACTION 语句显式开始,以 COMMIT 或 ROLLBACK 语句显式结束。

  隐式事务:在前一个事务完成时新事务隐式启动,但每个事务仍以 COMMIT 或 ROLLBACK 语句显式完成。

  批处理级事务:只能应用于多个活动结果集 (MARS),在 MARS 会话中启动的 Transact-SQL 显式或隐式事务变为批处理级事务。在sql server 2000 必须对每个 SqlCommand 对象使用独立的 SqlConnection 对象。但是 SQL Server 2005 启用了 MARS,可以共用一个SqlConnection 对象。

       本章重点讲到显式事务的隔离级别

关于数据库事务隔离级别的介绍

MSSQL锁定-1.隔离级别 Isolation level
MSSQL锁定-2.Transaction
MSSQL锁定-3.死锁与阻塞

1   概述

二. 事务并发模型

  2.1 并发访问是指:多用户同时访问一种资源被视为并发访问资源。 并发数据访问需要某些机制,以防止多个用户试图修改其他用户正在使用的资源时产生负面影响,机制就是下面讲的事务隔离级别。处于活动状态而不互相干涉的并发用户数据越多,并发性就越好。当一个正在修改数据的用户阻止了其他用户读取数据,或者当一个正在读取数据的用户阻止了其它用户修改数据时,并发性就降低了。

  2.2 并发类型

    在sqlserver里数据库系统可以采用两种方式来管理并发数据访问:乐观并发控制和悲观并发控制,在sql server 2000以前只有悲观并发。乐观并发控制是一种称为行版本控制(row versioning)的技术支持。这二种技术并发控制的区别在于:是在冲突发生前进行防止,还是在发生后采用某种方法来处理冲突。

  悲观并发控制

      在悲观并发中,sql server是获取锁来阻塞对于其它用户正在使用数据的访问。  用户操作的读与写之间是会互相阻塞的。

       乐观并发控制

    乐观并发控制默认采用行版本控制使其它用户能够看到修改操作发生以前的数据状态,旧版本数据行会保存下来。因些读取数据不会受到其它用户正对该数据进行修改操作的影响,换言之修改数据不会受到其它用户正对该数据进行读取影响。 因为读取用户访问的数据行是一个被保存过的版本。  用户读与写之间不会互相阻塞,但写与写还是会发生阻塞。

  2.3  事务并发带来的负面影响

       修改数据的用户会影响同时读取或修改相同数据的其他用户。 即这些用户可以并发访问数据。 如果数据存储系统没有并发控制,则用户可能会看到以下负面影响:

并发影响 

定义

丢失更新                                                            

       当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。 每个事务都不知道其他事务的存在。   最后的更新 将覆盖由其他事务所做的更新,这将导致数据丢失。 

脏读

 当一个用户修改了数据但尚未提交修改,而另一个正在读取的用户会读到这个修改从而导致不一致的状态发生。

不可重复读

一个用户在同一个事务中分别以两个读操作间隔读取相同资源时可能会得到不同的值。

虚拟读取(幻影)

一个事务里执行两个相同的查询,但第二个查询返回的行集合是不同的,此时就会发生虚拟读取。这种情况发生在where 查询中,比如 where count(1)<10。  同一个事务中多次使用相同的条件查询,select操作返回不同数据的结果集。

事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。例如,银行转账工作:从一个账号扣款并使另一个账号增款,这两个操作要么都执行,要么都不执行。所以,应该把它们看成一个事务。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。

--Ref

本篇文章简要对事物与锁的分析比较详细,因此就转载了。

三.事务隔离级别

  在sql server 2005及以上 支持五种隔离级别来控制“读”操作的行为,其中有三个是悲观并发模式,一个是乐观并发模式,剩下一个存在两种模式。 下面介绍隔离级别从允许的并发负作用(例如脏读或虚拟读取)的角度进行描述。

隔离级别

 定义

未提交读
READUNCOMMITTED 

 隔离事务的最低级别,未提交读不会发出共享锁,允许脏读,一个事务可能看见其他事务所做的尚未提交的更改。未提交读不会发出共享锁. 该项的作用与与SELECT表上加NOLOCK相同。

 

已提交读
READ COMMITTED

 一个事务不能读取其它事务修改但未提交的数据,避免了脏读。事务内语句运行完后便会释放共享锁,而不是等到事务提交的时候。 这是数据库引擎默认级别。

可重复读
REPEATABLE READ

 事务内查询语句运行完后不会释放共享锁,而是等到事务提交后.其它事务不能修改,删除,但可以插入新数据。
 因为不是范围锁,可能发生虚拟读取

 可序列化SERIALIZABLE

 隔离事务的最高级别,事务之间完全隔离。 阻止其它事务删除或插入任何行。 相当于SELECT上加HOLDLOCK相同, SELECT 操作使用 WHERE 子句时获取范围锁,主要为了避免虚拟读取

已提交读 快照隔离
READ COMMITTED SNAPSHOT ISOLATION level (RCSI)

当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 时,已提交读隔离使用行版本控制提供语句级读取一致性。 读取操作只需要 SCH-S 表级别的锁,不需要页锁或行锁。 使用行版本控制为每个语句提供一个在事务上一致的数据快照,因为该数据在语句开始时就存在。 

快照隔离
SNAPSHOT ISOLATION level
(SI)

 快照隔离级别使用行版本控制来提供事务级别的读取一致性。 读取操作不获取页锁或行锁,只获取 SCH-S 表锁。 读取其他事务修改的行时,读取操作将检索启动事务时存在的行的版本。 当 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON 时,只能对数据库使用快照隔离。 默认情况下,用户数据库的此选项设置为 OFF。

  sql server主要是通过共享锁申请和释放机制的不同处理,来实现不同的事务隔离级别。不同隔离级别允许的并发副作用如下:

隔离级别 脏读 不可重复读 幻影读 并发控制模型
 未提交读 悲观
 已提交读 悲观
 已提交读快照 乐观
 可重复读 悲观
 快照 乐观
可串行化 悲观

  不同隔离级别对共享锁的不同处理方式如下:

隔离级别 是否申请共享锁 何时释放 有无范围锁
未提交读  
已提交读 当前语句做完时
可重复读 事务提交时
可序列化 事务提交时

针对上面的描述可以看出,事务的提出主要是为了解决并发情况下保持数据一致性的问题。

  • 并发的影响:
    该文章列出了并发引起的四种影响:丢失更新、脏读(未提交的依赖关系)、不可重复读(不一致的分析)、幻读
  • 并发控制类型:
    当许多人试图同时修改数据库中的数据时,必须实现一个控制系统,使一个人所做的修改不会对他人所做的修改产生负面影响。这称为并发控制。并发控制类型分为两大类:乐观并发控制和悲观并发控制

2   具体内容

四.事务隔离不同表现

* *  设置未提交读 

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

 设置提交读 

SET TRANSACTION ISOLATION LEVEL READ COMMITTED 

    设置可重复读

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 

   4.1 未提交读和提交读与其它事务并发,的区别如下表格:

未提交读

提交读

其它事务


SELECT Model FROM Product

WHERE SID=10905

显示model 值为test


SELECT Model FROM Product 

WHERE SID=10905

显示model 值为test

begin  tran

update  product set model='test1'

where SID=10905

SET TRANSACTION ISOLATION
LEVEL READ UNCOMMITTED

SET TRANSACTION ISOLATION 

LEVEL READ COMMITTED

 这个事务将model值改为test1.

 此时修改的X锁未释放

 

SELECT Model FROM Product

WHERE SID=10905

显示model值为test1,但这并不正确,

因为其它事务还没有提交。没有获取共享锁

 

SELECT Model FROM Product

WHERE SID=10905

查询被阻塞

申请获取共享锁时失败,因为X锁未释放

 

  阻塞消失,得到的值还是test

 rollback tran

这里事务回滚了x锁释放,值还是test

   4.2  已提交读和可重复读与其它事务并发,的区别如下表格:

已提交读

可重复读 其它事务

SET TRANSACTION ISOLATION
LEVEL READ UNCOMMITTED
begin tran
SELECT Model FROM
ProductWHERE SID=10905
第一次查询显示model值为 test

SET TRANSACTION ISOLATION
LEVEL REPEATABLE READ
begin tran
SELECT Model FROM Product
WHERE SID=10905
第一次查询显示model值为 test

 

   

begin tran
update product set model='test1'
where SID=10905
将model值改为 test1

另一事务是已提交读时,这里事务修改成功
提交读共享锁查询后就释放。

另一事务是可重复读时,这里事务修改阻塞
可重复读共享锁一直保留到事务提交

SELECT Model FROM Product
WHERE SID=10905
第二次查询值显示为 test1

SELECT Model FROM Product
WHERE SID=10905
第二次查询显示值显示为 test

 

commit tran

这里就是一个事务里多次读取同一值
结果可能不一致

  commit tran  

   未完...sql server 锁与事务拨云见日(下)

事务具有以下4个基本特征。

--一、数据库事务 

并发可以定义为多个进程同时访问或修改共享数据的能力。处于活动状态而互不干涉的并发用户进程的数量越多,数据库系统的并发性就越好。当一个正在修改数据的进程阻止了其他进程读取该数据,或者当一个正在读取数据的进程阻止了其他进程修改该数据,并发性就降低了。本文用术语“读取”或者“访问”描述数据上的SELECT操作,用“写入”或“修改”描述数据上的INSERT,UPDATE以及DELETE操作。

● Atomic(原子性):事务中包含的操作被看做一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。

事务是作为单个逻辑工作单元执行的一系列操作。可以是一条SQL语句也可以是多条SQL语句。

一般地,数据库系统可以采用两种方式来管理并发数据访问,乐观并发控制和悲观并发控制。

● Consistency(一致性):只有合法的数据可以被写入数据库,否则事务应该将其回滚到最初状态。

in a multi-user application env, transactions, locking mechanisms, isolation levels and wait mode

并发控制模型

对于任何一种并发控制模式,如果两个事务试图同一时刻修改数据的话都会产生冲突。这两种模式之间的区别在于,是在冲突发生前进行防止,还是发生后采取某种方法来处理冲突。

● Isolation(隔离性):事务允许多个用户对同一个数据进行并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。

一个支持事务(Transaction)的数据库系统,必需要具有这四种特性,否则在事务过程(Transaction processing)当中,无法保证数据的正确性。

悲观并发控制

对于悲观并发控制,该模型假定系统中存在足够多的数据修改操作,以致于事务的任何数据读取/修改操作都可能受到其他事务数据修改操作的影响,即假定冲突总是会发生的。SQL Server默认通过(lock)来保证读者和写者之间的互斥。

● Durability(持久性):事务结束后,事务处理的结果必须能够得到固化。

原子性 Atomicity: 一个操作一样不被打断 BEGIN...END. The transaction is either performed entirely or not performed at all

乐观并发控制

对于乐观并发控制,该模型假定系统中存在非常少的相互冲突的数据修改操作,以致任何单独的事务都不太可能修改其它事务正在修改的数据。乐观并发控制默认采用行版本控制来处理并发。

例如,在读取数据时我们会得到一个数据的版本version 1,当需要修改数据时,我们先检查数据的版本是不是version 1,如果是就修改数据;如果不是,就说明在当前事务的读操作和写操作之间已经有别的事务对数据进行了修改(每次修改操作都会使得数据的版本+1),SQL Server将会产生一个错误消息,由上层应用程序响应此错误。

数据库肯定是要被广大客户所共享访问的,那么在数据库操作过程中很可能出现以下几种不确定情况。

一致性Consistency: If the database was consistent before the execution of the transaction .It should remain consistent after the complete execution of that transaction.

事务处理

无论是采用哪种并发控制模型,对于事务的理解是至关重要的。事务是SQL Server中任务的基本单位。典型地,它由几个读取和修改数据的SQL命令组成,但是直到COMMIT命令被执行以后,修改操作才被认为是终结了。

● 更新丢失(Lost update):两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。这是因为系统没有执行任何的锁操作,因此并发事务并没有被隔离开来。

隔离性 Isolation: The transaction should not be interfered by any other transaction executing concurrently.

ACID属性

原子性(Atomicity) SQL Server保证事务的原子性。原子性指的是每个事务要么全部执行,要么什么都不执行。也就是说,如果一个事务提交了,它造成的所有效果都会被保留。如果中止了,其所有效果都会被撤销。

一致性(Consistency) 一致性属性确保事务不允许系统到达一个不准确的逻辑状态——数据必须总是保持逻辑上的正确。即使在发生系统故障时,约束和规则必须得到保证。(一致性一般被原子性、隔离性以及持久性所涵盖,并且概念上会产生重复)

隔离性(Isolation)
隔离性会将并发事务与其他并发事务的更新操作分隔开。当该事务正在执行时,其他事务是无法看到进行中的任务的。SQL Server会在事务之间自动实现隔离。它采用锁定数据或者行版本使得多个并发事务能够并发操作数据,以防止导致不正确结果。

隔离性意味着事务必须在不干扰其他事务的前提下独立执行。换言之,在事务执行完毕之前,其所访问的数据不能受系统其他部分的影响。

持久性(Durability) 当事务提交之后,SQL Server的持久性属性就会确保该事务的作用持续存在(即使发生系统故障)。如果在事务进行过程中发生系统故障,事务就会被完全撤销,不会在数据上遗留部分作用。如果在事务的提交确认被发送到调用的程序之后立刻发生故障,数据库会确保该事务的存在。预写式日志以及SQL Server启动恢复阶段的事务自动回滚/自动重做机制能够确保持久性。

● 脏读取(Dirty Reads):一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。

持久性 Durability: The changes made by the transaction should be permanently committed in the database.

一致性问题

事务总是全部支持ACID属性的。事务可能还会表现出一些另外的行为,称为“一致性问题”,而我并不认为它们是“问题”。它们仅仅是可能存在的行为,而用户能够决定允许哪些和阻止哪些,用户对于隔离级别的选择决定了下列这些行为中哪些是被允许的。

● 不可重复读取(Non-repeatable Reads):一个事务对同一行数据重复读取两次,但是却得到了不同的结果。例如,在两次读取的中途,有另外一个事务对该行数据进行了修改,并提交。

(另外的描述:多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,不合理的存取和不完整的读取数据)

丢失更新

当两个事务读取相同数据并且都处理该数据(修改了它的值),然后都尝试更新原来的数据成新的值时,这种行为就会发生了。第二个事务可能完全覆盖掉第一个所完成的更新。

时间 取款事务A 取款事务B
T1 开始事务  
T2   开始事务
T3   查询账户余额为1000
T4 查询账户余额为1000  
T5   取出100,存款余额为900
T6 取出300,存款余额为700  
T7 提交事务  
T8   提交事务

最终账户余额为900,取款事务A的更新丢失了。丢失更新是这些行为中唯一一个用户可能在所有情况下都想避免的行为。

● 两次更新问题(Second lost updates problem):无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。

启动事务:使用 API 函数和 Transact-SQL 语句,可以按显式、自动提交或隐式的方式来启动事务。

脏读

这种行为在一个事务读取未提交数据时会发生,如果一个事务修改了数据但是尚未提交修改,而另一个正在读取数据的事务会读到这个修改从而导致一种不一致的状态发生。

时间 查询事务A 取款事务B
T1 开始事务  
T2   开始事务
T3   查询账户余额为1000
T4   取出100,存款余额为900
T5 查询账户余额为900  
T6   撤销事务,恢复为1000
T7 提交事务  

查询事务A读取到取款事务B还未提交的余额900。
默认情况下,脏读是不允许的。谨记:更新数据的事务是无法控制别的事务在它提交之前读取其数据的,这是由读取数据的事务来决定是否想要读取未必会被提交的数据。

● 虚读(Phantom Reads):事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。

结束事务:您可以使用 COMMIT(成功) 或 ROLLBACK(失败) 语句,或者通过 API 函数来结束事务。

不可重复读

这种行为又被称为“不一致分析”。如果同一事务分别以两个读操作读取相同资源时,可能会得到不同的值,这就是不可重复读。

时间 查询事务A 取款事务B
T1 开始事务  
T2   开始事务
T3 查询账户余额为1000  
T4   取出100,存款余额为900
T5 查询账户余额为900  
T6   提交事务
T7 提交事务  

查询事务A两次读取余额获取到不同结果。

数据库的隔离级别

创建事务的原则:尽可能使事务保持简短很重要,当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源、以保证事务的正确安全执行。特别是在大量并发的系统中, 保持事务简短以减少并发 资源锁定争夺,将先得更为重要。

幻读

这种行为产生于一个数据集内的部分数据被修改时。如果事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。

时间 取款记录处理事务A 取款事务B
T1 开始事务  
T2   开始事务
T3 查询到5条取款记录  
T4   查询余额为1000元
T5   取出100,存款余额为900
T6 查询到6条取款记录  
T7 提交事务  
T8   提交事务

对于取款记录处理事务A,两次查询的结果集不同。

 

事务的行为取决于隔离级别,也就是决定上述四种行为中那些是被允许的。并发控制模型决定了隔离级别是如何实现的——或者更明确的讲,决定了SQL Sever是如何确保用户所不想要的行为不发生的。

为了避免上面出现的几种情况,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。

           1、事务处理,禁止与用户交互,在事务开始前完成用户输入。

隔离级别

SQL Server支持五种隔离级别来控制读操作的行为。其中三个只在悲观并发模型中可用,一个只在乐观并发模型中可用。剩下的一个在两个模式下都是可用的。

葡京正网网投 1

● 未授权读取(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个数据则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。

           2、在浏览数据时,尽量不要打开事务

未提交读

除了丢失更新以外,上面提到的其他行为都可能发生。未提交读是通过使读操作不占用任何锁来实现的,当前事务能够读取其他事务已经修改过但是尚未提交的数据。

当采用未提交读时,用户是放弃了对高一致性数据的把握而趋向于支持系统的高并发能力,使用户不会再互相锁定对方。那么,何时才应该选择未提交读呢?显然,每笔数据都须保证平衡的金融交易是不适合的。而对于某些决策支持分析来说可能会很适合(譬如,需要察看销售走势时),因为完全没有必要做到完全精确而且会带来并发性能的提升,因此是相当值得的。

● 授权读取(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。

           3、尽可能使事务保持简短。

已提交读

已提交读是数据库引擎的默认级别。SQL Server 2005支持两种已提交读的隔离级别,这种隔离级别既可以是乐观的也可以是悲观的,默认采用悲观并发控制。为了区分,悲观实现称“已提交读(锁定)”,乐观实现称为”已提交读(快照)”。

已提交读隔离级别保证了一个操作不会读到别的程序已经修改但是尚未提交的数据。如果别的事务正在更新数据并因此在数据行上持有排它锁,当前的事务就必须等待这些锁释放后才能使用这个数据(无论是读取还是修改)。同样地,事务必须至少在要被访问的数据上加上共享锁,其他事务可以读取数据但是不能修改数据。默认,共享锁在数据读取过后就被释放掉,而无需在事务的持续时间内保留。

已提交读(快照),也能保证一个操作不会读到未提交数据,但不是通过迫使其他进程等待的方式。对于已提交读(快照),每当一行数据被修改后,SQL Server就会生成该行数据前一次已提交值的一个版本(version),被修改的数据仍旧被锁定着,但是其他进程可以看到该数据在更新操作开始之前的版本。

● 可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

           4、考虑为只读查询使用快照隔离,以减少阻塞。

可重复读

可重复读是一种悲观的隔离级别。它在已提交读的基础上增加了新的属性:确保当事务重新访问数据或查询被再一次执行时,数据将不再发生改变。换句话说,在一个事务中执行相同的查询两次是不会看到由其他事务所造成的任何数据的改变的。然而,可重复读隔离级别还是允许幻读的出现。

在某些情况下,防止不可重复读是用户向往的一种安全措施。但是世上没有免费的午餐,这种额外的措施所带来的开销是事务中所有的共享锁必须保留到事务完成为止。

排它锁必须总是保留到事务结束为止,无论采用何种隔离级别或者并发模型,这样事务才能在需要时被回滚。如果锁提前释放了,就不太可能完成撤销操作,因为其他并发事务可能已经使用了同一数据,并且修改了它的值。
只要事务是打开的,没有其他用户可以修改被该事务所访问的数据。显然这会严重降低并发性和性能。因此,如果事务不保持简短或者编写应用程序时没有能够注意到这样潜在的锁竞争问题,将会导致大量的事务因为等待锁释放而挂起。

● 序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。

           5、灵活地使用更低的事务隔离级别。

快照

快照隔离是一种乐观隔离级别,类似于已提交读(快照),如果当前版本被锁定住时,它允许其他事务读取已提交数据的早期版本。快照隔离和已提交读(快照)的区别与(早期版本该有多早、保留多少个早期版本)这个问题相关,我们在行版本控制小节中详述。尽管快照隔离所避免的行为和可串行化所避免的是相同的,但是快照隔离并不是真正意义上的可串行化隔离级别。对于快照隔离,可能会有两个个事务同时执行,并引起一个任何序列化执行都不可能产生的结果。

葡京正网网投 2

如果两个事务并行地运行,最终会交换titles表里两本书的价格。然而,不存在一种序列化执行的方式最终导致数值的交换。无论是先执行事务1然后执行事务2,还是先执行事务2再执行事务1,任何序列顺序最终将导致两本书拥有相同的价格。

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

           6、灵活地使用更低的游标并发选项,例如开放式并发选项。

可串行化

可串行化也是一种悲观隔离级别。可串行化隔离级别在可重复读的基础上增加了新的属性:确保在重新执行查询时,SQL Server不会在中间的过渡期增加新的行。换句话说,如果同一事物在相同的查询被执行两次的话,幻读不会出现。可串行化也因此成为最健壮的悲观隔离级别,因为防止了之前所描述的所有可能的“不一致问题“。

额外的安全措施必定会带来额外的开销。可串行化隔离级别下,事务中的所有共享锁都必须保留到事务完成为止。另外,执行可串行化隔离级别不仅需要锁定已读数据,还需要锁定那些不存在的数据,参看后面的键范围锁。

葡京正网网投 3

通过前面的介绍已经知道,通过选用不同的隔离等级就可以在不同程度上避免前面所提及的在事务处理中所面临的各种问题。所以,数据库隔离级别的选取就显得尤为重要,在选取数据库的隔离级别时,应该注意以下几个处理的原则:

           7、在事务中尽量使访问的数据量最小。

锁定

对于多用户数据库系统而言,锁定是一个至关重要的功能。锁在悲观和乐观并发控制模型中都有所应用,尽管在每种模型中其他事务处理“被锁定数据”的方式是不同的。在悲观模型中,写者总是阻塞读者和写者,而读者也会阻塞写者。对于乐观模型,唯一可能发生的阻塞是写者阻塞其他写者。

首先,必须排除“未授权读取”,因为在多个事务之间使用它将会是非常危险的。事务的回滚操作或失败将会影响到其他并发事务。第一个事务的回滚将会完全将其他事务的操作清除,甚至使数据库处在一个不一致的状态。很可能一个已回滚为结束的事务对数据的修改最后却修改提交了,因为“未授权读取”允许其他事务读取数据,最后整个错误状态在其他事务之间传播开来。

--数据库事务

锁定的基本概念

SQL Server可以使用几种不同方式来锁定数据,举例来说,读操作获取共享锁而写操作获取排他锁。更新锁在更新操作的开头部分获取。SQL Server会自动获取并释放所有这些类型的锁。它还负责管理锁定模式之间的兼容性,解决死锁问题,并在需要的时候进行锁升级。它在表、表的分页、索引键以及单独的数据行上支配锁。

其次,绝大部分应用都无须使用“序列化”隔离(一般来说,读取幻影数据并不是一个问题),此隔离级别也难以测量。目前使用序列化隔离的应用中,一般都使用悲观锁,这样强行使所有事务都序列化执行。

事务是作为单个逻辑工作单元执行的一系列操作.可以是一条SQL语句也可以是多条SQL语句.一个支持事务 Transaction的数据库系统,必需要具有这四种特性,以保证保证数据的正确性

锁定类型

剩下的也就是在“授权读取”和“可重复读取”之间选择了。我们先考虑可重复读取。如果所有的数据访问都是在统一的原子数据库事务中,此隔离级别将消除一个事务在另外一个并发事务过程中覆盖数据的可能性(第二个事务更新丢失问题)。这是一个非常重要的问题,但是使用可重复读取并不是解决问题的唯一途径。

  • 原子性 Atomicity: 一个操作一样不被打断 BEGIN...END. The transaction is either performed entirely or not performed at all
  • 一致性Consistency: If the database was consistent before the execution of the transaction .It should remain consistent after the complete execution of that transaction.
  • 隔离性 Isolation: The transaction should not be interfered by any other transaction executing concurrently.
  • 持久性 Durability: The changes made by the transaction should be permanently committed in the database.
    (另外的描述:多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,不合理的存取和不完整的读取数据)

共享锁

当数据被读取时,SQL Server自动获取共享锁。许多事务可以在同一数据上都持有共享锁,但是没有事务可以在已经有一个共享锁存在的情况下,在该数据上再获取一个排他锁。一般的,当数据已经读取完毕后,共享受就会立即释放掉,但是可以通过使用查询提示或者采用不同的事务隔离级别来改变这种默认方式。

假设使用了“版本数据”,Hibernate会自动使用版本数据。Hibernate的一级Session缓存和版本数据已经为你提供了“可重复读取隔离”绝大部分的特性。特别是,版本数据可以防止二次更新丢失的问题,一级Session缓存可以保证持久载入数据的状态与其他事务对数据的修改隔离开来,因此如果使用对所有的数据库事务采用授权读取隔离和版本数据是行得通的。

数据库在多任务交互的时候,需要用以下4中机制来保护数据库的正确运行,他们是:transactions, locking mechanisms, isolation levels and wait mode

排它锁

当数据被插入、更新或者删除操作修改以后,SQL Server就会自动获取数据上的排他锁。一次只能有一个事务持有特定数据资源上的排它锁。排它锁会保留到事务结束为止。这就意味着被修改的数据通常在当前事务提交或者回滚之前对其他事务来说是不可用的。其他事务可以通过使用查询提示来读取被排它锁锁定的数据。

“可重复读取”为数据库查询提供了更好的效率(仅对那些长时间的数据库事务),但是由于幻影读取依然存在,因此没必要使用它(对于Web应用来说,一般也很少在一个数据库事务中对同一个表查询两次)。

启动事务:使用 API 函数和 Transact-SQL 语句,可以按显式、自动提交或隐式的方式来启动事务。结束事务:您可以使用 COMMIT(成功) 或 ROLLBACK(失败) 语句,或者通过 API 函数来结束事务。创建事务的原则:尽可能使事务保持简短很重要,当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源、以保证事务的正确安全执行。特别是在大量并发的系统中, 保持事务简短以减少并发 资源锁定争夺,将先得更为重要。

更新锁

更新锁实际上并不是一种独立的锁,他是共享锁和排他锁的一种混合。当SQL Server执行一个数据修改操作但是首先需要搜索表以寻找到被修改的资源时,更新锁就会被获取。更新锁能够预防锁升级而产生的死锁,SQL Server保证更新锁的持有者能够将其转化成排他锁,死锁就可以避免了。

葡京正网网投 4

 

更新锁本身不足以使用户能够修改数据——所有的数据修改都要求被修改的数据资源上存在一个排它锁。只要有一个事务对资源持有更新锁,其它事务就无法获取该资源的更新锁或者排他锁了。持有更新锁的事务能够将其转换成该资源上的排它锁,因为更新锁避免了与其他进程之间的锁的不兼容。可以将更新锁看作是“意图更新锁”,这才是它实际所扮演的角色。更新锁会保留到事务结束或者当它转换成排他锁。

不要被锁的名字误导,更新锁并不只是针对更新操作而设计的。SQL Server使用更新锁适用于任何需要进行实际修改之前搜索数据的数据修改操作。这样的操作包括受限更新及删除,也包括在带有聚集索引的表上进行的插入操作。对于后面一种情况,SQL Server必须先搜索数据(使用聚集索引)以找到正确的位置来插入新的记录。当SQL Server只进行到搜索阶段时,它会采用更新锁来保护数据,而只有当它找到正确的位置并开始插入以后才将更新锁升级为排他锁。

也可以同时考虑选择使用Hibernate的二级缓存,它可以如同底层的数据库事务一样提供相同的事务隔离,但是它可能弱化隔离。假如在二级缓存大量使用缓存并发策略,它并不提供重复读取语义(例如,后面章节中将要讨论的读写,特别是非严格读写),很容易可以选择默认的隔离级别:因为无论如何都无法实现“可重复读取”,因此就更没有必要拖慢数据库了。另一方面,可能对关键类不采用二级缓存,或者采用一个完全的事务缓存,提供“可重复读取隔离”。那么在业务中需要使用到“可重复读取”吗?如果你喜欢,当然可以那样做,但更多的时候并没有必要花费这个代价。

  1.  事务处理,禁止与用户交互,在事务开始前完成用户输入
  2. 在浏览数据时,尽量不要打开事务
  3. 尽可能使事务保持简短
  4. 考虑为只读查询使用快照隔离,以减少阻塞
  5. 灵活地使用更低的事务隔离级别
  6. 灵活地使用更低的游标并发选项,例如开放式并发选项
  7. 在事务中尽量使访问的数据量最小

意向锁

意向锁实际上并不是一种独立的锁定模式。你可以拥有意向共享锁,意向排他锁甚至意向更新锁。由于SQL Server可以在不同级别的粒度上获取锁,因此需要一种机制来指出一个资源上的组件已经被锁定了。例如,如果一个事务试图锁定一张表,SQL Server需要采用一种机制来判断是否这张表上的行(或者一个分页)已经被锁住了。意向锁就是起这个作用,在了解锁的粒度时会深入研究意向锁。

一、数据库事务
1、事务是作为单个逻辑工作单元执行的一系列操作。可以是一条SQL语句也可以是多条SQL语句。
2、事务具有四个特性
原子性:不可分隔、成则具成、败则具败。
隔离性:独立的执行互不干扰。由并发事务所作的修改必须与任何其他并发事务所作的修改隔离(另外的描述:多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,不合理的存取和不完整的读取数据)
3、启动事务:使用 API 函数和 Transact-SQL 语句,可以按显式、自动提交或隐式的方式来启动事务。
4、结束事务:您可以使用 COMMIT(成功) 或 ROLLBACK(失败) 语句,或者通过 API 函数来结束事务。
5、创建事务的原则:
尽可能使事务保持简短很重要,当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源、以保证事务的正确安全执行。
特别是在大量并发的系统中, 保持事务简短以减少并发 资源锁定争夺,将先得更为重要。
1、事务处理,禁止与用户交互,在事务开始前完成用户输入。
2、在浏览数据时,尽量不要打开事务
3、尽可能使事务保持简短。
4、考虑为只读查询使用快照隔离,以减少阻塞。
5、灵活地使用更低的事务隔离级别。
6、灵活地使用更低的游标并发选项,例如开放式并发选项。
7、在事务中尽量使访问的数据量最小。

--事务的隔离级别

键范围锁

只在可串行化隔离级别中为了锁定一定范围内的数据而被获取。共享锁和排它锁可以在表、分页、行或者键上获取,而键锁只能从键上获取。

二、事务的隔离级别

隔离级别与并发性是互为矛盾的:隔离程度越高,数据库的并发性越差;隔离程度越低,数据库的并发性越好。ANSI/ISO SQ92标准定义了一些数据库操作的隔离级别:

锁的粒度

SQL Server可以锁定表、分页、行等级别的数据资源。它同样可以锁定索引键及一定范围内的索引键。谨记如果表上存在聚集索引,数据行就在聚集索引的叶级,并且是由键锁而不是行锁来锁定它们的。

 

葡京正网网投 5

SQL Server对每个锁都进行追踪并且包含了锁、被锁定资源(行、键或分页)、锁的模式以及特定资源的一个标识符。当一个事务申请锁时,SQL Server会将所申请的锁与已经申请的锁进行比较并寻找完全匹配资源类型以及标识符的锁。但是,如果一个事务在表中的某行上占有一个排他锁,别的事务可能会尝试在整张表上获取一个锁。

 

由于是两种不同的资源,SQL Server不会找到一个完全的匹配,这就需要使用意向锁了。SQL Server会记录在表的一行记录上拥有排他锁的事务也在包含该行记录的分页上占有一个意向锁,以及在包含该行记录的这张表上拥有一个意向锁。当其他事务试图获取这张表上的一个排他锁时,其他事务将会被阻塞。

1、数据库事务的隔离级别:四种

     隔离级别                脏读(Dirty Read) 不可重复读(NonRepeatable Read) 幻读(Phantom Read)

键锁

SQL Server支持两种类型的键锁,而它采用哪种类型则取决于当前事务的隔离级别。如果隔离级别是已经提交读、可重复读或者快照,SQL Server会在处理查询时尝试锁定实际被访问的索引键。对于聚集索引的表而言,数据行就是索引的叶级别,而用户可以看到所获取的键锁。如果表是堆结构的话,用户可能会看到非聚集索引上的键锁以及实际数据上的行锁。

如果隔离级别是可串行化,情况就有所不同了。为了防止幻读,如果一个事务中扫描了一个范围内的数据就需要充分锁定住该表以确保没人能够插入新值到已扫描的范围内。在SQL Server早期版本中是通过锁定整个分页甚至整张表来保证这一点的。在许多情况下,这可能导致了更大范围的数据被锁定住了,造成了不必要的资源竞争。SQL Server 2005采用了一种称为“键范围锁”的单独锁模式,与索引中的特定键值相关联并表明在索引中这两个键之间的所有值被锁定住了。

           

读未提交(Read uncommitted)      可能                   可能                         可能

锁的兼容性

锁简称

葡京正网网投 6

简单兼容性矩阵

葡京正网网投 7

完整兼容性矩阵

葡京正网网投 8

  

 读已提交(Read committed)       不可能                  可能                          可能

行级锁定VS分页锁定

锁粒度越小,加锁操作越频繁,管理锁带来的开销就越大。但是,锁粒度越小,冲突率越小,并发性能会更好。每种类型的锁定在针对不同类型的程序和处理方法时都会显示出其独特的优势,因此选中那种类型的锁定,取决于应用程序和数据。

隔离级别

  可重复读(Repeatable read)      不可能                 不可能                         可能

锁升级

SQL Server在适当的时候会自动将行、键或者分页级锁升级为粒度更粗的表级锁。这种升级保护了系统资源(防止系统使用太多的内存在追踪锁),并且提高了效率。例如,在一个查询获取许多行级锁后,锁级别可以升级为表级锁,因为这时获取并持有一个单独的表级锁比持有许多行级锁可能更有意义。

  

      可串行化(Serializable )        不可能                 不可能                        不可能

死锁

葡京网投哪个正规,当两个事务都在等待获取资源,但是由于相互阻碍对方获取资源导致没有事务能够前进时就会发生死锁。

葡京正网网投 9

葡京正网网投 10

  

先看横向的:

行级版本控制

乐观并发控制采用了一种称为行版本控制的新技术来保障事务。在使用乐观锁并发控制时会获取排他锁。乐观并发和悲观并发的区别在于乐观并发中写操作与读操作之间不会互相阻塞。换句话说就是,当被请求资源当前拥有共享锁时,申请排它锁的事务不会被阻塞,相反,当被请求资源当前拥有排他锁时,申请共享锁的进程也不会被阻塞。

一旦启用乐观并反控制,SQL Server就使用tempdb数据库来存储所有已经修改过的记录的副本,并且只要存在来自任意事务的访问需求,就会继续维持这些副本。当tempdb用来存储被修改记录的早期版本时,就其称为版本存储区

脏读(Dirty    Read)

  • 脏读dirty reads:当事务读取还未被提交的数据时,就会发生这种事件。举例来说:Transaction1修改了一行数据,然后Transaction2在 Transaction1还未提交修改操作之前读取了被修改的行。如果Transaction1回滚了修改操作,那么Transaction2读取的数据就可以看作是从未存在过的。
  • 不可重复的读non-repeatable reads:当事务两次读取同一行数据,但每次得到的数据都不一样时,就会发生这种事件。举例来说:Transaction1读取一行数据,然后 Transaction2修改或删除该行并提交修改操作。当Transaction1试图重新读取该行时,它就会得到不同的数据值(如果该行被更新)或发现该行不再存在(如果该行被删除)。    
  • 虚读phantom read:如果符合搜索条件的一行数据在后面的读取操作中出现,但该行数据却不属于最初的数据,就会发生这种事件。举例来说Transactio1读取满足某种搜索条件的一些行,然后Transaction2插入了符合Transaction1的搜索条件的一个新行。如果Transaction1重新执行产生原来那些行的查询,就会得到不同的行。

行版本控制的实现

SQL Server引入了一种新的隔离级别:快照隔离以及一种新式的无阻塞风格的已提交读隔离——已提交读(快照)。这些基于版本控制的隔离级别允许读者获取行的一个先前已提交过的值而不会产生阻塞,这样就提高了系统的并发能力。为了使它起作用,SQL Server必须在行被修改或删除时保留旧版本的记录。如果在同一行上进行多次更新,SQL Server就可能需要维护该行的多个早起版本。鉴于此,行版本控制有时也被称为多版并发控制。

当表或索引中的一行数据被更新时,SQL Server会用执行更新的那个事务的事务序列号来标记新的行。事务序列号是一个单调递增的数字,在每个SQL Server的实例中保证唯一。在更新一行数据时,之前的版本存放在版本存储区内,而新的行包含一个指向版本存储区中旧的行数据的指针。版本存储区里旧的行数据可能包含了指向更早版本的指针。一条行记录的所有版本串接成一个链表。SQL Server可能需要沿着链表中的几个指针才能到达一个正确的版本,只要有操作需要引用它们,行的版本就必须在版本存储区内保存。

葡京正网网投 11

在应用程序使用默认的悲观模型造成的并发性下降而不能令人满意时,SQL Server可以改用乐观并发控制模型。在切换到基于乐观版本控制的隔离级别之前,用户必须仔细权衡使用新型并发模型的效果。处理需要额外的管理来为版本存储区监控tempdb以外,鉴于维护旧版本锁带来的额外工作量,版本控制还会降低更新操作的性能。即使当前没有人在读取数据,更新操作也得为此买单。如果有使用行版本控制的读操作,它们必须花费额外的开销来遍历链表指针,以找到需要的行数据的合适版本。

另外,由于快照隔离的乐观并发模型假定系统不会发生很多的更新冲突,如果用户预见到在同一数据上的并发更新会产生竞争,就不应该选择快照隔离级别。快照隔离级别能够使读者不被写者阻塞,但是并发的写者仍然不被允许。在默认的悲观模型中,第一个写者会阻塞所有的后续写者,但如果采用快照隔离,后续写者实际上会接受到错误消息且应用程序需要重新提交初始请求。

葡京正网网投,  

再看纵向的:以下4种隔离级别都会以创建事务的测试步骤来进行测试
设置事务级别:SET TRANSACTION ISOLATION LEVEL
开始事务:begin tran
提交事务:COMMIT
回滚事务:ROLLBACK
创建事务保存点:SAVE TRANSACTION savepoint_name
回滚到事务点:ROLLBACK TRANSACTION savepoint_name

基于快照的隔离级别

  

  • Read Uncommitted (Oracle不支持):最低等级的事务隔离,仅仅保证了读取过程中不会读取到非法数据。上诉4种不确定情况均有可能发生。
    与READ COMMITTED 隔离级相反它允许读取已经被其它用户修改但尚未提交确定的数据限制级别最小,脏读在这个隔离级别下是非Consistent Reads的

  • Read Committed (SQL Server, Oracle默认):大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了"脏读取",该级别适用于大多数系统.

    SQL Server> SET TRANSACTION ISOLATION LEVEL 
               {READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE}
    和S锁类似,在此隔离级下SELECT 命令不会返回尚未提交的数据,也不能返回脏数据.
    
    MySQL中类似select ... for update, select ... lock in share mode
    
    Oracle> SET TRANSACTION ISOLATION LEVEL {READ COMMITTED | READ ONLY | SERIALIZABLE};
    Oracle> ATER SESSION SET ISOLATION_LEVE {READ COMMITTED | SERIALIZABLE};
    事务只能读取已经提交的数据
    -- updated 2009-09-15 from《Expert Oracle Database Architecture》P233
    

    例子

    第一个查询事务
        SET TRANSACTION ISOLATION LEVEL Read Committed
        begin tran
           update Cate SET Sname=Sname+'b' where ID=1
           SELECT * FROM cate where ID=1
           waitfor delay '00:00:6'  
           rollback tran --回滚事务
        select Getdate()
        SELECT * FROM cate where ID=1
    第二个查询事务
        SET TRANSACTION ISOLATION LEVEL Read Committed 
          --把committed换成Read uncommitted可看到“脏读取”的示例。
        SELECT * FROM cate where ID=1
        select Getdate()
          --可以看到使用 Read Committed 成功的避免了“脏读取”.
    
  • Repeatable Read (MySQL默认,Oracle不支持):保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。

    mysql> SELECT @@global.tx_isolation;
    mysql> set { global | session } transaction isolation level read committed;
    mysql> set autocommit = 0;
    在此隔离级下用SELECT 命令读取的数据在整个命令执行过程中不会被更改,其他事务不能执行Update和Delete,
    但是可以Insert。此选项会影响系统的效能,非必要情况最好不用此隔离级;
    

    例子

    第一个查询事务
        SET TRANSACTION ISOLATION LEVEL Repeatable Read 
          --把Repeatable Read换成Read committed可以看到“不可重复读取”的示例
        begin tran
        SELECT * FROM cate where ID=33 --第一次读取数据
           waitfor delay '00:00:6'  
        SELECT * FROM cate where ID=33 --第二次读取数据,不可重复读取
        commit
    第二个查询事务
        SET TRANSACTION ISOLATION LEVEL Read Committed
        update cate set Sname=Sname+'JD' where ID=33
        SELECT * FROM cate where ID>30
    

       

  • Serializable (Oracle中Read only和这个很相似,唯一区别是Read only事务不允许修改,因此不会遇到ORA-08177错误):
  • 最高等级的事务隔离,上面3种不确定情况都将被规避。这个级别将模拟事务的串行执行。-- updated 2009-09-15 from《Expert Oracle Database Architecture》P239
    这是最大的限制,和X锁类似,不允许其他事务进行任何写访问。如非必要,不要使用这个选项。在事务的开始使用这个命令即可,该隔离级别一直对该SQL Server连接(不是本事务)有效,直到下一次使用本命令设置了新的隔离级别为止。

    在第一个查询窗口执行
        SET TRANSACTION ISOLATION LEVEL Serializable 
          -- 把Serializable换成Repeatable Read 可看到“幻像读”的示例
        begin tran
        SELECT * FROM cate where ID>30 --第一次读取数据,“幻像读”的示例
           waitfor delay '00:00:6'   --延迟6秒读取
        SELECT * FROM cate where ID>30 --第一次读取数据
        commit
    第二个查询事务
        SET TRANSACTION ISOLATION LEVEL Read Committed
        Delete from cate where ID>33
        SELECT * FROM cate where ID>30
    
  • 例如,如果将事务隔离级别设置为 SERIALIZABLE,并且在 SELECT 语句中使用表级锁定提示 NOLOCK,则键范围锁通常用于维护不采用可串行事务。

      USE   pubs   
      GO   
      SET   TRANSACTION   ISOLATION   LEVEL   SERIALIZABLE   
      GO   
      BEGIN   TRANSACTION   
      SELECT   au_lname   FROM   authors   WITH   (NOLOCK)   
      GO   
    
    --生成的锁是:     
      EXEC   sp_lock   
      spid   dbid   ObjId   IndId   Type   Resource   Mode   Status     
      1   1   0   0   DB     S   GRANT     
      6   1   0   0   DB     S   GRANT     
      7   1   0   0   DB     S   GRANT     
      8   4   0   0   DB     S   GRANT     
      8   4   0   0   DB     S   GRANT     
      8   4   117575457   0   TAB     Sch-S   GRANT     
      9   4   0   0   DB     S   GRANT     
      9   1   21575115   0   TAB     IS   GRANT     
      SELECT   object_name(117575457)   
      GO   
      -----------------------------   
      authors   
    --引用   authors   唯一采用的锁是架构稳定性   (Sch-S)   锁。在这种情况下不能保证可串行性。
    

已提交读快照隔离(RCSI)

已提交读快照隔离是一种语句级的快照隔离,也就是任何查询都能看到在语句开始那一刻最近提交过的数值。假设在启用了RCSI的数据库上有如下两个事务,且在事务开始运行之前Product 922的ListPrice值是8.89

葡京正网网投 12

注意当时间为2时,事务1所作出的修改尚未提交,因此Product ID=922的行上仍然持有锁。但是事务2不会被这个锁阻塞住,它能够访问该行数据上一次已提交的ListPrice值8.89。这仍然属于已提交读隔离级别(一个无阻塞的变种),所以不能防止“不可重复读”。

RCSI最大的益处是可以引入更好的并发性,因为读者与写者之间不会相互阻塞。但是写者之间还是会发生阻塞,因此标准的加锁机制适用于全部的更新、删除和插入操作。

不可重复读(NonRepeatable    Read)

 --问题

快照隔离(SI)

SI提供了数据的一种事务一致性视图。任何读取操作都将得到在事务开始那一刻最近已提交过的数据版本(对于RCSI,会得到在语句开始那一刻最近已提交过的数据版本)。需要谨记的一个要点:事务并不是从BEGIN TRAN语句开始的,对于SI来说,事务是在第一次访问数据库内任意数据的时候才开始的。

葡京正网网投 13

葡京正网网投 14

尽管事务1已经提交了,事务2继续返回它读到的初始值8.99,直到事务2完成为止。只有在事务2完成以后,该链接才能读到ListPrice的新值。

  

  • 问题1:

    create table test (id int identity, c varchar(10));
    --使用默认隔离机制
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    --session 1:
    begin tran
    insert into test values (1);
    --session 2:
    select * from test
    --在SQL Server05内session 1提交之前,此查询被block住
    --在Oracle内session 1提交之前,此查询不会被block住
    

    为什么?

  • 问题2:第三个session 不停的查询,偶尔会发现这样的现象:读取时发现自增列有间断,比如第N次读,读到了id=1001的记录但未读到 id=1000的记录,但下次读时读到了这条记录。这是怎么回事? 难道是因为id=1001的记录在第N次读时已经提交 而id=1000的未提交?
    但按照问题1中的现象当有未提交事务时第N次读应该block住,要等待id=1000的事务提交后才能执行啊,这时应该能读到id=100
    答:就是sql的读一致性和oracle不同, 无论查询执行多常时间、查询如何多的记录,oracle能够保证读一致性,即读到的所有记录都是在select查询开始执行那一刻的状态(snapshot),读不到之后的修改(即使提交);sql server则不是这样,它的select能够读到在它开始执行之后提交的事务修改

    1,insert/update产生的锁会block住select(如查询这行的话),这和oracle不一样;oracle是不会block select的;
    2,就是sql的读一致性和oracle不同,无论查询执行多常时间、查询如何多的记录,oracle能够保证读一致性,即读到的所有记录都是在select查询开始执行那一刻的状态(snapshot),读不到之后的修改(即使提交);sql server则不是这样,它的select能够读到在它开始执行之后提交的事务修改2000的时候,读写会堵塞的,2005的时候,学oracle了,增强了多版本控制和快照
    xxd:可是我测试了一下,2005下还是阻塞

更新冲突

两种乐观并发级别之间的重要区别在于:SI可能会造成潜在的更新冲突。

葡京正网网投 15

冲突发生是因为事务2在Quantity值为324的时候开始,当这个值被事务1更新后,行版本324被存储到版本存储区内。事务2会在事务的持续时间内继续读取该行数据。如果两个更新操作都被允许成功执行的话,就会产生经典的更新丢失情形。事务1增加了200个数量,然后事务2会在初始值上增加300个数量并存储。由第一个事务增加的那200个产品就会彻底丢失,SQL Server不会允许这样的情况发生。

当事务2开始尝试执行更新时,并不会立刻得到一个错误——仅仅是被阻塞。事务1在行上拥有一个排他锁,因此事务2尝试获取排他锁时会被阻塞。如果事务1回滚,那么事务2就能够完成更新。但事务1最终被提交了,SQL Server检测到一个冲突并产生错误。

冲突只可能发生在SI模式下,因为SI隔离级别是基于事务而不是基于语句的。如果上述例子在一个采用RCSI的数据库中执行,事务2执行的更新语句不会使用该数据的原来值。当试图读取当前的Quantity值时,它会被阻塞住,而接着事务1完成时,它就能读取更新过的Quantity将其作为当前值并再增加300,没有一个更新会丢失。

如果用户选择工作在SI模式下就需要注意可能发生的冲突,它们能够被减少到最低限度,但是如同死锁一样,用户不能保证不发生冲突。用户必须写程序来合理地处理冲突,并且不能想当然地认为更新已经成功了。如果冲突只是偶然发生,用户可能需要将其作为使用SI模式的部分代价考虑在内,但如果冲突太过频繁,就需要额外措施来避免冲突。

3   参考文献

 【01】

4   版权

 

  • 感谢您的阅读,若有不足之处,欢迎指教,共同学习、共同进步。
  • 博主网址:
  • 极少部分文章利用读书、参考、引用、抄袭、复制和粘贴等多种方式整合而成的,大部分为原创。
  • 如您喜欢,麻烦推荐一下;如您有新想法,欢迎提出,邮箱:2016177728@qq.com。
  • 可以转载该博客,但必须著名博客来源。

  

幻读(Phantom    Read)

  

读未提交(Read uncommitted)

可能

可能

可能

读已提交(Read committed)

不可能

可能

可能

可重复读(Repeatable read)

不可能

不可能

可能

可串行化(Serializable )

不可能

不可能

不可能

2、数据库一般的默认隔离离级别是“读已提交”,默认的事务隔离级别下:Insert,update ,delete下的是X锁, 会等待事务完成。通常情况下可以把隔离级别设为Read Commited,它能避免脏读,而且有较好的并发性能。尽管它会导致不可重复读、虚读和第二类更新丢失等问题,在可能出现这类问题的个别场合可以由应用程序釆用悲观锁或乐观锁来控制。

3、SQL语句可以使用SET TRANSACTION ISOLATION LEVEL来设置事务的隔离级别。如:SET TRANSACTION ISOLATION LEVEL Read Committed。若要在应用程序中使用更严格或较宽松的隔离级别,可以通过使用 set transaction isolation level语句设置会话的隔离级别,来自定义整个会话的锁定。
指定隔离级别后,sql server会话中所有select语句的锁定行为都运行于该隔离级别上,并一直保持有效直到会话终止或者将隔离级别设置为另一个级别。

4、另外要提一点:SQL标准对事务隔离级别的规定,是按该级别不可能发生什么问题来确定的,不一定会发生这样的问题;所以,不同的数据库对事务隔离的级别约定不一样,比如,有的数据库把 可重复读级别按可串行化来对待。(lkdlhw_2000个人理解:各个数据库应该都遵循四种标准的事务隔离等级的定义,但是某些数据库具体实现可能不存在四种,因为串行化可以避免不可重复读,因此某些数据库语法上支持设置事务隔离等级为不可重复读,但实际上是串行化在起作用。也就是说只要该级别能够避免不可重复读的问题,就可以称之为不可重复读取级别。)

5、该隔离级别定义一个事务必须与其他事务所进行的资源或数据更改相隔离的程度。事务隔离级别控制:
读取数据时是否占用锁以及所请求的锁类型。
占用读取锁的时间。
引用其他事务修改的行的读取操作是否:
在该行上的排他锁被释放之前阻塞其他事务。
检索在启动语句或事务时存在的行的已提交版本。
读取未提交的数据修改

三、锁

1、分类:从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁

2、事务使用锁,防止其他用户修改另外一个还没有完成的事务中的数据。对于多用户系统来说,锁机制是必须的。SQL Server有多种锁,允许事务锁定不同的资源。锁就是保护指定的资源,不被其他事务操作。SQL Server有多种锁,允许事务锁定不同的资源。锁就是保护指定的资源,不被其他事务操作。为了最小化锁的成本,SQL Server自动地以与任务相应等级的锁来锁定资源对象。锁定比较小的对象,例如锁定行,虽然可以提高并发性,但是却有较高的开支,因为如果锁定许多行,那么需要占有更多的锁。锁定比较大的对象,例如锁定表,会大大降低并发性,因为锁定整个表就限制了其他事务访问该表的其他部分,但是成本开支比较低,因为只需维护比较少的锁。

3、 锁的特点:

  1. 锁是保证并发控制的手段
  2. 可以锁定的资源包括行、页、簇、表和数据库
  3. 锁的类型主要包括共享锁和排它锁
  4. 特殊类型的锁包括意图锁、修改锁和模式锁
  5. 共享锁允许其他事务继续使用锁定的资源
  6. 排它锁只允许一个事务访问数据
  7. 系统本身可以处理死锁
  8. 用户可以根据实际情况定制锁的一些特征

4、锁是定义到sql语句上的,对数据进行操作的sql就是:select,Insert,update ,delete。不同的事物隔离即被在执行sql的时候会向表上发送不同的锁。

四、多个用户同时对数据库的并发操作时会带来以下数据不一致的问题:

脏读dirty reads:
当事务读取还未被提交的数据时,就会发生这种事件。举例来说:Transaction1修改了一行数据,然后Transaction2在Transaction1还未提交修改操作之前读取了被修改的行。如果Transaction1回滚了修改操作,那么Transaction2读取的数据就可以看作是从未存在过的。
不可重复的读non-repeatable reads:
当事务两次读取同一行数据,但每次得到的数据都不一样时,就会发生这种事件。举例来说:Transaction1读取一行数据,然后Transaction2修改或删除该行并提交修改操作。当Transaction1试图重新读取该行时,它就会得到不同的数据值(如果该行被更新)或发现该行不再存在(如果该行被删除)。
虚读phantom read:
如果符合搜索条件的一行数据在后面的读取操作中出现,但该行数据却不属于最初的数据,就会发生这种事件。举例来说Transactio1读取满足某种搜索条件的一些行,然后Transaction2插入了符合Transaction1的搜索条件的一个新行。如果Transaction1重新执行产生原来那些行的查询,就会得到不同的行。

为了解决这些问题,数据库引入了“锁”的机制(从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁,详细内容不再描述)。

五、lkdlhw_2000个人理解(以下问题都是推测,还没有证实):

隔离级别是由锁来实现的,之所以出现事务的隔离级别相当于数据库开发商根据一般的业务需求实现定义好的一组锁使用的规则,便于我们时候,当我们将事务隔离级别定义到某一级上后如果不能满足需求,我们还可以自行定义sql的锁来覆盖事务隔离级别默认的锁机制?

锁存在两个问题:一个是锁的粒度,一个是锁的时间,锁的时间应该包括两种一种是sql执行完就释放锁,领一中是事务结束后释放锁

六、事务隔离级别的例子

  1. Read Uncommitted:最低等级的事务隔离,仅仅保证了读取过程中不会读取到非法数据。上诉4种不确定情况均有可能发生。
  2. Read Committed:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
    第一个查询事务
    SET TRANSACTION ISOLATION LEVEL Read Committed
    begin tran
    update Cate SET Sname=Sname+'b' where ID=1
    SELECT * FROM cate where ID=1
    waitfor delay '00:00:6'
    rollback tran --回滚事务
    select Getdate()
    SELECT * FROM cate where ID=1
    第二个查询事务
    SET TRANSACTION ISOLATION LEVEL Read committed --把committed换成Read uncommitted可看到“脏读取”的示例。
    SELECT * FROM cate where ID=1
    select Getdate()
    可以看到使用 Read Committed 成功的避免了“脏读取”.
  3. Repeatable Read:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
    第一个查询事务
    SET TRANSACTION ISOLATION LEVEL Repeatable Read -- 把Repeatable Read换成Read committed可以看到“不可重复读取”的示例
    begin tran
    SELECT * FROM cate where ID=33 --第一次读取数据
    waitfor delay '00:00:6'
    SELECT * FROM cate where ID=33 --第二次读取数据,不可重复读取
    commit
    第二个查询事务
    SET TRANSACTION ISOLATION LEVEL Read committed
    update cate set Sname=Sname+'JD' where ID=33
    SELECT * FROM cate where ID>30
    4. Serializable:最高等级的事务隔离,上面3种不确定情况都将被规避。这个级别将模拟事务的串行执行。
    在第一个查询窗口执行
    SET TRANSACTION ISOLATION LEVEL Serializable -- 把Serializable换成Repeatable Read 可看到“幻像读”的示例
    begin tran
    SELECT * FROM cate where ID>30 --第一次读取数据,“幻像读”的示例
    waitfor delay '00:00:6' --延迟6秒读取
    SELECT * FROM cate where ID>30 --第一次读取数据
    commit
    第二个查询事务
    SET TRANSACTION ISOLATION LEVEL Read committed
    Delete from cate where ID>33
    SELECT * FROM cate where ID>30
    创建事务

设置事务级别:SET TRANSACTION ISOLATION LEVEL
开始事务:begin tran
提交事务:COMMIT
回滚事务:ROLLBACK
创建事务保存点:SAVE TRANSACTION savepoint_name
回滚到事务点:ROLLBACK TRANSACTION savepoint_name

 

本文由葡京网投哪个正规发布于新葡亰-数据,转载请注明出处:【葡京网投哪个正规】锁与事务拨云见日,事物与锁

关键词:

上一篇:没有了

下一篇:一千行MySQL学习笔记【葡京网投哪个正规】