wns9778.com_威尼斯wns.9778官网

热门关键词: wns9778.com,威尼斯wns.9778官网
wns9778.com > 计算机教程 > 事务的隔离级别

原标题:事务的隔离级别

浏览次数:192 时间:2019-05-11

1.事务

事务的隔离级别

在sql  servce 中 事务是一个工作单元 可能包含查询和修改数据以及修改数据定义等多个活动 也可以显示或隐式定义事务边界

SQL Server通过在锁资源上使用不同类型的锁来隔离事务。为了开发安全的事务,定义事务内容以及应在何种情况下回滚至关重要,定义如何以及在多长时间内在事务中保持锁定也同等重要。这由隔离级别决定。应用不同的隔离级别,SQL Server赋予开发者一种能力,让他们为每一个单独事务定义与其他事务的隔离程度。事务隔离级别的定义如下:

显示定义事务 BEGIN TRAN 开始  如果要提交事务 使用 COMMIT TRAN   撤销事务(回滚) ROLLBACK TRAN  如下示例

  • 是否在读数据的时候使用锁

  • 读锁持续多长时间

  • 在读数据的时候使用何种类型的锁

BEGIN TRAN;
INSERT INTO Sales.Orders
      (custid, empid, orderdate, requireddate, shippeddate, 
       shipperid, freight, shipname, shipaddress, shipcity,
       shippostalcode, shipcountry)
    VALUES
      (85, 5, '20090212', '20090301', '20090216',
       3, 32.38, N'Ship to 85-B', N'6789 rue de l''Abbaye', N'Reims',
       N'10345', N'France');
commit tran

   

一个简单的显示事务    也可以是隐式事务

  • 读操作希望读已经被其他事务排他锁住的数据时,怎么办?在这种情况下,SQL Server可以:

    • 一直等到其他事务释放锁

    • 读没有提交的数据

    • 读数据最后提交后的版本

GO
 INSERT INTO Sales.Orders
      (custid, empid, orderdate, requireddate, shippeddate, 
       shipperid, freight, shipname, shipaddress, shipcity,
       shippostalcode, shipcountry)
    VALUES
      (85, 5, '20090212', '20090301', '20090216',
       3, 32.38, N'Ship to 85-B', N'6789 rue de l''Abbaye', N'Reims',
       N'10345', N'France');
GO

ANSI 99定义了4种事务隔离级别,SQL Server 2005能够完全支持这些级别:

通过GO 在当前批执行完成时自动 提交事务   当然默认情况下SQL Server 将每个单独的语句作为一个事务 每个语句结束后SQL Server 会自动提交事务 也可通过设置会话来改变默认设置 

  • 未提交读 在读数据时不会检查或使用任何锁。因此,在这种隔离级别中可能读取到没有提交的数据。

  • 已提交读 只读取提交的数据并等待其他事务释放排他锁。读数据的共享锁在读操作完成后立即释放。已提交读是SQL Server的默认隔离级别。

  • 可重复读 像已提交读级别那样读数据,但会保持共享锁直到事务结束。

  • 可序列化 工作方式类似于可重复读。但它不仅会锁定受影响的数据,还会锁定这个范围。这就阻止了新数据插入查询所涉及的范围,这种情况可以导致幻像读。

SET IMPLICIT_TRANSACTIONS ON

   

设置为ON 后不需要指定BEGIN TRAN 语句开始事务 但必须以COMMIT TRAN或 TOLLBACK TRAN 标记结束

此外,SQL Server还有两种使用行版本控制来读取数据的事务级别(本章后文将详细检验这些隔离级别)。行版本控制允许一个事务在数据排他锁定后读取数据的最后提交版本。由于不必等待到锁释放就可进行读操作,因此查询性能得以大大增强。这两种隔离级别如下:

事务有4个属性-原子性,一致性,隔离性,持续性 首字母缩写为ACID

  • 已提交读快照 它是一种提交读级别的新实现。不像一般的提交读级别,SQL Server会读取最后提交的版本并因此不必在进行读操作时等待直到锁被释放。这个级别可以替代提交读级别。

  • 快照 这种隔离使用行版本来提供事务级别的读取一致性。这意味着在一个事务中,由于读一致性可以通过行版本控制实现,因此同样的数据总是可以像在可序列化级别上一样被读取而不必为防止来自其他事务的更改而被锁定。

原子性(Atomicity)**: 事务是一个原子工作单元,事务中的所有修改要么提交,要么撤销。在事务提交指令记录到事务日志之前 如果系统出现了故障,重新启动时,SQL Server 会撤销所做的修改。  如果事务中出现错误 默认会自动回滚   也可以通过 @@TRANCOUNT 检测事务事务完成 或者说是 当前环境是否在事务中 如果在就返回 1 没有就是0 

   

SELECT    @@TRANCOUNT

无论定义什么隔离级别,对数据的更改总是通过排他锁来锁定并直到事务结束时才释放。

一致性(Consistency):指数据状态, 在隔离级别中  每个级别都要是 一致性级别 只有事务保持一致性级别才能访问。在约束中 也指 主外键 书屋会转换数据库的一致性状态到另一个一致性状态 保持一致性

很多情况下,定义正确的隔离级别并不是一个简单的决定。作为一种通用的规则,要选择在尽可能短的时间内锁住最少数据,但同时依然可以为事务提供它所需的安全程度的隔离级别。

隔离性(Isolation):隔离是一种控制访问数据的机制,确保事务所范围数据是在其所期望的一致性级别中的数据。在SQL Server 中支持两种不同的模式来处理隔离:基于锁的传统模式和行版本控制(新模式) 但是默认的是 锁模式  而且当前加锁也是共享锁 ,如果数据状态不一致 读取数据就会被阻止 直到状态一致 。而改成行版本控制模式 读取就不需要等待 也不会加共享锁 在不需要及时显示的数据时 这种模式是提高并发的处理方式。 具体实现要看使用的隔离级别。

已提交读

持续性(Durability):数据修改在写入到数据库磁盘之前,总是先写入数据库的事务日志磁盘。提交后,指令记录在事务日志磁盘上,在尚未修改磁盘数据之前,事务是持续的,回滚也只是删除事务日志的所有修改记录。

在SQL Server 2005中,已提交读隔离级别是建立连接时的默认隔离级别。这个级别存在两种类型:已提交读和已提交读快照隔离级别。应用哪种类型由数据库选项定义。已提交读级别会在读数据之前等待,直到阻塞锁被释放。已提交读快照级别会在数据被其他事务阻塞时使用行版本控制来读数据最后一次提交的版本。

下面是一个完整的事务示例:

使用已提交读级别:

BEGIN TRAN;

  DECLARE @neworderid AS INT;


BEGIN TRY
  INSERT INTO Sales.Orders
      (custid, empid, orderdate, requireddate, shippeddate, 
       shipperid, freight, shipname, shipaddress, shipcity,
       shippostalcode, shipcountry)
    VALUES
      (85, 5, '20090212', '20090301', '20090216',
       3, 32.38, N'Ship to 85-B', N'6789 rue de l''Abbaye', N'Reims',
       N'10345', N'France');

  SET @neworderid = SCOPE_IDENTITY();

  SELECT @neworderid AS neworderid;

  INSERT INTO Sales.OrderDetails(orderid, productid, unitprice, qty, discount)
    VALUES(@neworderid, 11, 14.00, 12, 0.000),
          (@neworderid, 42, 9.80, 10, 0.000),
          (@neworderid, 72, 34.80, 5, 0.000);

COMMIT TRAN;
END TRY
BEGIN CATCH
ROLLBACK TRAN;
END CATCH

BEGIN TRAN

2.锁

   

锁是事务保护数据资源而获得的控制资源,防止其他事务的冲突或不兼容访问。

SELECT

锁主要有两种锁模式 排他锁和共享锁

    FirstName, LastName, EmailAddress

当你试图修改数据时 事务会请求数据资源的一个排他锁,它会一直到事务结束才会解除 期间任何其他事务请求都会被阻塞。对于单条语句事务 只要这条语句结束锁就会自动解除。对于多条语句事务 就只有当他完成所有语句执行并通过 COMMIT TRAN 或 ROLLBACK TRAN 命令时事务才会解除锁

FROM

排他锁:如果一个事务在修改行,直到事务完成,其他事务都不能修改相同的行。但是能不能读取相同行 取决于它的隔离级别。

    Person.Contact

共享锁:在读取事务加锁是默认加的是共享锁  SQL读取的默认隔离级别 READ COMMITTED  因为此隔离级别 会让事务请求读取资源时默认加上共享锁  多个事务可以同时拥有相同数据资源共享锁。 此模式下也会因为并发造成幻读 虽然在修改数据时,无法修改锁和持续时间,但可以通过改变隔离级别 在读取数据时控制锁定的处理方式。

WHERE

其实锁的本质就是数据的隔离级别 在通过控制隔离级别也能达到加锁的效果 ,而且效果更好。

ContactID = 1

在SQL 中默认的隔离级别 READ COMMITTED SNAPSHOT 这种隔离依靠行版本控制,而不是锁,在此模式下 读取者不需要共享锁,因为不需要等待,依赖行版本控制技术提供隔离。   如果一个事务在READ COMMITTED隔离级别下 修改数据行 直到事务完成,另一个事务都不能读取相同行。这种并发控制称 “悲观式并发”  如果一个事务在READ COMMITTED SNAPSHOT隔离级别下 修改数据行  此时另一个事务读取相同行 会获得最后一次提交的可用状态。这种并发控制称 “乐观式并发” 在乐观并发中可以很好的解决修改和展示并发问题。

   

  这种事务之间的并发处理已称为 锁兼容性

    返回EmailAddress为gustavo0@adventure-works.com的联系人Gustavo Achong。

 

现在假设另一事务在事务打开状态下更改了EmailAddress。打开第二个查询窗口并执行以下批来UPDATE EmailAddress,但不提交事务:

请求锁模式 请求排他锁 请求共享锁
请求排他锁
请求共享锁

USE AdventureWorks;

交叉的否代表不兼容 请求锁模式会被拒绝 交叉是 表示兼容 请求锁模式会被接收

   

那么锁都可以锁些什么资源呢?

BEGIN TRAN

锁定的资源包括RID ,键,行,页,对象,表,数据库,范围,分配单元,堆,B树。

UPDATE

锁请求流程规则是什么呢?

    Person.Contact

例如:获取一个行上的排他锁  事务必须首先获取一个行所在页的意向排他锁和一个拥有该页对象的意向排他锁, 同样的 共享锁也是此步骤。

SET

为什么要申请意向锁?

    EmailAddress = 'uncommitted@email.at'

为了在更高级别有效的检测是否有锁不兼容请求,并防止授予这些锁请求,这就是为什么在排他锁请求相同数据行时被阻断的原因。

WHERE

例如:一个事务持有行上锁,而另一个事务在该行所在的页或者表请求不兼容锁比如排他锁 有第一个事务的行上锁 有一个 表意向锁  这个时候请求就被拒绝了

    ContactID = 1

但意向锁不会拒绝更低级别对象的锁请求  

    这个UPDATE 语句会正常运行。一行受到了影响,即使数据在这个事务还没有运行完之前已被查询窗口1中的事务读取。因为已提交读级别并不会在事务结束前保持用于SELECT语句的共享锁。共享锁会在数据读取之后立即被SQL Server释放。需要一致读的时候这将是一个问题。我们将下面的"获取一致的可重复读操作"实现。

例如: 一个页上的意向锁不会阻断在该页的其他事务的排他锁  我们可以通过一个表来细致的了解这些锁的兼容性请求。

    现在切换到查询窗口1并尝试再次读数据:

请求锁模式 请求排他锁 请求共享锁 请求意向排他锁 请求意向共享锁
请求排它锁
请求共享锁
请求意向排他锁
请求意向共享锁

    SELECT

 

        FirstName, LastName, EmailAddress

 

FROM

通过这些锁得到我们最理想的并发处理 锁定所需要的内容,即受影响行数 。锁是需要内存资源和内部管理开销, 当需要锁时要考虑当前系统资源情况。

        Person.Contact

有一个情况不得不说  在行锁中超过5000个时 会自动升级锁 到表锁 然后每加1250个锁都会触发默认的锁升级

WHERE

可以通过ALTER TABLE语句设置LOCK_ESCALATION 的表选项控制锁升级。 也可以禁用。 也可以更改升级方式 比如 分区级别( 把一个表物理的组织成小单元c成为分区)   锁到此语句结束了下次讲  如何优雅的排除并发导致的阻塞数据处理。

        ContactID = 1

 

   

    由于SELECT语句被阻塞,因此这个查询并没有结束。SQL Server会尝试在ContactID= 1的键上获取一个共享锁,但是由于在查询窗口2中的UPDATE语句对其有一个排他锁,因此这个操作不可能完成。虽然查询窗口2处于已提交读级别(由于您没有更改默认级别),但排他锁依然存在。这个阻塞将持续存在,因为数据更改的排他锁会一直保持直到事务结束。

切换到查询窗口2,让查询窗口1中的查询继续运行。键入并执行以下SELECT语句检查数据库中的授权和等待的锁。

可以看一个状态为WAIT的共享锁。这是查询窗口1中运行的查询。它在等待查询窗口2中的查询,后者在同样的资源上有一个排他锁。

在查询窗口2中执行一个ROLLBACK TRAN语句来回滚UPDATE语句。然后切换回查询窗口1。可以看到,查询窗口1中的查询完成了,并且其结果与以前的一样。查询窗口2中的事务结束的时候,锁被释放了,以至查询窗口1中的查询不再被阻塞。由于查询窗口2中的事务回滚,因此查询窗口1中得到的结果是原来的数据。如果查询窗口2中的事务被提交,则查询窗口1中会得到新的数据作为结果。

在查询窗口1中执行一个COMMIT TRAN语句并关闭所有的查询窗口。

可以看出,在(默认)已提交读级别中SQL Server会等到排他锁释放之后再进行读操作,以此来获取真正的提交数据。还可以看出,共享锁会持续到数据被读取之后,而排他锁会持续到事务提交之后。在许多事务几乎同时更改数据的时候这种行为可能会造成问题。在这些情况下,由于排他锁造成的阻塞,读数据会非常慢。但在有些情况下,使用最后提交的数据版本是恰当的。在这些情况下,可以将已提交读级别更改为已提交读快照级别。

如果要在窗口1读取数据的话,可以使用这样的方法:

SELECT

    FirstName, LastName, EmailAddress

FROM

    Person.Contact WITH (NOLOCK)

WHERE

    ContactID = 1

    让它取消所有的锁机制,那么排他锁也不会影响到这句查询。

    使用NOLOCK注意:在 SQL Server 中,NOLOCK 提示将启用"未提交读"行为。在 SQL Server Mobile 中,使用 NOLOCK 提示仍会赋予"提交读"隔离级别。SQL Server Mobile将维护数据副本,以确保可以读取数据而不需要使用共享锁帮助保护数据。

使用已提交读快照级别

激活已提交读快照级别

USE master;

ALTER DATABASE AdventureWorks

SET READ_COMMITTED_SNAPSHOT ON

    注意:设置 READ_COMMITTED_SNAPSHOT 选项时,数据库中仅允许存在执行 ALTER DATABASE 命令的连接。在 ALTER DATABASE 完成之前,数据库中不允许有其他打开的连接。数据库不必处于单用户模式。

现在,执行以下代码开始一个事务并像前面一样更改EmailAddress(但要让事务处于打开状态):

USE AdventureWorks;

BEGIN TRAN

UPDATE Person.Contact

SET EmailAddress = 'uncommitted@email.at'

WHERE ContactID = 1;

打开第二个查询窗口并执行以下语句来读取ContactID 1的列Name和EmailAddress列。

    USE AdventureWorks;

BEGIN TRAN

SELECT FirstName, LastName, EmailAddress

FROM Person.Contact

WHERE ContactID = 1;

返回了联系人Gustavo Achong的EmailAddress gustavo0@adventure-works.com,这是这一行最后提交的版本。不像没有快照的已提交读级别那样,这个查询不会被阻塞。关闭查询窗口2并切换到查询窗口1。

执行以下语句来回滚事务并切换回已提交读级别(这个查询将等待直到关闭查询窗口2):

ROLLBACK TRAN

GO

USE master;

ALTER DATABASE AdventureWorks

SET READ_COMMITTED_SNAPSHOT OFF

重要提示 这个隔离级别可以用于减少阻塞。但要意识到这是一个数据库选项。当它发生了更改,将在数据库系统中使用已提交读级别的所有事务也会改变它们的行为。因此,只有在所有这些事务读最后提交的数据版本与读真正提交的数据版本在逻辑上同样正确的时候,使用这种级别才是明智的。

获取一致的可重复读操作

已提交读级别的一个缺点是,一个事务读取的数据在事务运行期间可能被另一个事务更改。因此,在两种已提交读级别下,不能保证一致性读。获取一致性读的意思是,在一个事务中,读取的数据始终是一样的。

1. 已提交读在读数据的时候使用共享锁,但在读操作完成后会立即释放这个锁。因此,其他事务可以更改刚被读过的数据。

2. 已提交读快照读取最后一次提交的数据版本。当它第二次读数据的时候,最后一次提交的版本可能由于第二个事务已经提交了对数据的更改而变成一个新版本。

本文由wns9778.com发布于计算机教程,转载请注明出处:事务的隔离级别

关键词: wns9778.com

上一篇:Windows窗体应用开发1,windows窗体应用开发wns9778

下一篇:没有了