• SQL事物隔离级别


    标准SQL定义了4个隔离级别

    Read uncommitted  未提交读

    Read committed    已提交读  

    Repeatable read    可重复读

    Serializable      可序列化

    基本语法

    SET TRANSACTION ISOLATION LEVEL 
        { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SNAPSHOT | SERIALIZABLE };

    1、READ UNCOMMITTED

    未提交读是最低的事务隔离级别,允许读取其他事务已经修改但未提交的数据行。在该隔离级别下,针对数据资源的读操作将不会申请共享锁,也不影响其他事物对该数据资源请求排他或独占锁,直接读取数据。在该事物隔离级别下,有可能读取到其他事物中修改但未提交的数据,因此这种读取也被称作脏读

    未提交读与NOLOCK语句具有相同的效果。

    CREATE TABLE Test
    (
        Id BIGINT PRIMARY KEY,
        Name NVARCHAR(20) DEFAULT NULL
    )

    往表中新增两条数据

    INSERT INTO Test VALUES(0,'陈楚生'),(1,'白百何')

    在事物A中更新Id为0的数据,但不提交

    BEGIN TRAN
    --在事物中修改Test中Id为0的数据,但不提交
    UPDATE Test SET Name='范玮琪' WHERE Id=0

    在事物B中使用未提交读级别查询Id为0的数据

    --使用未提交读级别将会读取到其他事物中未提交的修改,产生脏读
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    BEGIN TRAN
    SELECT * FROM Test WHERE Id=0
    COMMIT

    结果可见在事物B中读取到了事物A中未提交的修改。

    2、READ COMMITTED

    已提交读是大部分关系型数据库的默认事物隔离级别,在该级别下,只能读取到其他事物已提交的修改。当事务读取数据时,数据库引擎将放置共享锁以防止其他事务修改该数据,读取完成则释放共享锁,此时其他事物可以对数据继续进行修改。

    假如在一个事物A中,有两个相同的查询语句S1、S2,在已提交读级别下,当执行S1语句时,读操作将会申请共享锁,此时另一个事物B将智能对S1数据资源进行读操作,而不能进行写操作。待事物A中S1语句执行完毕之后,数据资源申请的共享锁被释放,此时假如B事物对S1语句的数据资源进行修改(共享锁已被释放,此时可以被修改),然后事物A继续执行S2,此时虽然S1语句和S2语句一样,但是由于在这两个语句之间,事物B对资源做了修改操作,就有可能导致S1、S2语句得到不一样的结果,这种现象叫不可重复读 

    在SQL SERVER 2005以上版本中,如果设置READ_COMMITTED_SNAPSHOT为ON,则在快照隔离级别下读操作不需要申请获得共享锁,也不影响其他事物对数据申请排他或独占锁,而且仍然可以得到和SERIALIZABLE与READ COMMITTED隔离级别类似的一致性;如果目前版本与预期的版本不一致,读操作可以从TEMPDB中获取预期的版本。

    在事物A中修改Id为0的数据,但不提交

    BEGIN TRAN
    --在事物中修改Test中Id为0的数据,但不提交
    UPDATE Test SET Name='范玮琪' WHERE Id=0

    在事物B中使用已提交读隔离级别读取Id为0的数据

    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    BEGIN TRAN
    SELECT * FROM Test WHERE Id=0
    COMMIT

    结果

    3、3.REPEATABLE READ

     在可重复读隔离级别下,对第一次的查询数据资源请求共享锁,并保留到事务结束,因此在整个事物过程中,重复查询相同记录时,不受其他事物的影响。但由于共享锁知道事务结束才会被释放,因此如果事务持续太久,将有可能影响到其他事物对这些数据的写入操作。【共享锁】

     在可重复读的隔离级别下查询Id为0的数据,但不提交

    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    BEGIN TRAN
    --查询结果为Id为1的数据,针对该数据数据库引擎将会放置共享锁
    --因此在其他事物中对Id为0的数据做修改或者新增新数据,都不受影响
    SELECT * FROM Test WHERE Id>0

    在另外一个事物中对Id为1的数据执行更新操作,此时因为Id为1数据上的共享锁跟随所在的事务释放,而事务未提交或回滚,因此该更新操作将不能执行。

    BEGIN TRAN
    UPDATE Test SET Name='范玮琪' WHERE Id=1
    COMMIT

    结果

    4、SERIALIZABLE

    在可重复读隔离级别下,数据库引擎将会锁定符合查询条件的数据资源,确保这些资源在事务周期内的一致性,但不能锁定查询结果之外的行。例如有两个事务A、B

    假如A的事物隔离级别为可重复读,并且在A中有两个相同的查询S1、S2,当执行S1语句时,数据库引擎将会在S1的数据资源上设置共享锁,

    因此其他事务中对该部分资源将智能查看而不能修改,此时事务B对资源表进行新增操作,并且新增的数据符合S1和S2的查询条件,然后事务A继续执行S2语句,

    此时S2结果将会与S1结果不同,这种现象称之为幻读。可序列化隔离级别与HOLDLOCK具有相同效果 

    在可序列化隔离级别下,将会对整个范围的资源添加区间锁,整个区间范围内的数据都将被锁定,直到事务被提交或回滚。

     在可序列化级别下,执行一个查询Id>0的操作,但不提交事务

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    BEGIN TRAN
    --查询结果为Id大于1的数据,都将被锁定,不能新增,修改,删除。
    SELECT * FROM Test WHERE Id>0

    在另外一个事物中执行新增Id=3的操作

    BEGIN TRAN
    INSERT INTO Test VALUES(3,'马天宇')
    COMMIT

    在另外一个事物中执行删除Id=2的操作

    BEGIN TRAN
    DELETE FROM Test WHERE Id=2
    COMMIT

    在另外一个事物中执行更新Id=2的操作

    BEGIN TRAN
    UPDATE Test SET Name='陈楚生' WHERE Id=2
    COMMIT

    结果都是

    可见在可序列化隔离级别下满足条件范围的资源都将被锁定

  • 相关阅读:
    非循环单链表节点的操作
    链表每一个节点的数据类型该如何表示
    链表的定义、确定一个链表需要几个参数?
    typedef的用法
    连续存储数组的算法(包含数组倒置、冒泡排序……)
    跨函数使用内存案例
    malloc()动态分配内存概述
    结构体
    指针和数组
    C#基础知识之dnSpy反编译
  • 原文地址:https://www.cnblogs.com/Jabben_Yi/p/5770933.html
Copyright © 2020-2023  润新知