---

2015/10/25

layout: post
title: "Sql中的ACID"
category: Reading Notes

tags: ["关系型数据库", "读文章"]

{% include JB/setup %}

理解原子性(Atomicity)

原子性意味着数据中的事务执行是作为原子。即不可再分,整个语句要么执行,要么不执行,不会有中间状态。

    CREATE TABLE  TestForAtom
    {
        col1 int
        CONSTRAINT chk_TestForAtom
        CHECK(col1 = 5)
    }

-- 插入的两个数据中有一个违反了check约束

    INSERT INTO TestForAtom(col1) values(5),(6)

-- 虽然有一条数据符合规范,但另一条数据6并不符合check约束

-- 从而造成没有任何数据可以插入,保证了原子性

    SELECT * FROM TestForAtom

SQL SERVER提供了两大类方式来保证自定义事务的原子性:
1. 通过SET XACT_ABORT ON来设置事务必须符合原子性
利用设置XACT_ABORT选项设置为ON,来设置所有事务都作为一个原子处理。

    SET XACT_ABORT ON
    BEGIN TRANSACTION
    -- 正确的语句
    INSERT INTO TestForAtom(col1)
    VALUES (5)
    -- 违反check约束的语句
    INSERT INTO TestForAtom(col1)
    VALUES (6)
    COMMIT
    go
    SELECT * FROM TestForAtom
  1. 按照用户设置进行回滚(ROLLBACK)
    这种方式具有更高的灵活性,开发人员可以自定义在什么情况进行ROLLBACK,利用TRY CATCH语句和@@ERROR进行判断都属于这种方式

    BEGIN TRANSACTION
    -- Try语句成功则Commit
    BEGIN TRY
    -- 正确的语句
    INSERT INTO TestForAtom(col1)
    VALUES (5)
    -- 违反check约束的语句
    INSERT INTO TestForAtom(col1)
    VALUES (6)
    COMMIT
    END TRY
    -- 捕捉到错误后执行Catch中的Rollback
    BEGIN CATCH
    ROLLBACK
    END CATCH
    

理解一致性(Consistency)

一致性,即在事务开始之前和事务结束之后,数据库的完整性约束没有被破坏。

一致性分成两个层面

  1. 数据库机制层面 数据库层面的一致性是,在一个事务执行之前和之后,数据会符合你设置的约束和触发器设置,这一点是有SQL SERVER进行保证的。
  2. 业务层面 对于业务层面来说,一致性是保持业务的一致性。这个业务一致性需要由开发人员进行保证,很多业务方面的一致性可以通过转移到数据库机制层面进行保证。比如,产品只有两个型号,则可以转移到使用CHECK约束使某一列必须只能村这两个型号。

理解隔离性(Isolation)

隔离性。事务的执行是互不干扰的,一个事务不可能看到其他事务运行时,中间某一时刻的数据。

事务之间的互相影响的情况分为几种,分别为脏读(Dirty Read),不可重复读,幻读

  • 脏读:脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚的。

两个事务,事务A插入一条数据,但未提交,事务B在此期间进行了读取,读取到了事务A未提交的数据,造成脏读。

  • 不可重复读(Unrepeatable Read):不可重复读意味着,在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。

事务B中对某个查询执行两次,当第一次执行完时,事务A对其数据进行了修改。事务B中再次查询时,数据发声了改变。

  • 幻读(phantom read):幻读是指事务不是独立执行时发生的一种现象。例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发声操作第一个事务的用户发现表中还有没有修改的数据行,就好像发声了幻觉一样。

事务B更新表中所有数据,在此期间事务A插入了一条数据,事务B再次查询后,发现居然还有没有修改的数据,产生幻读。

为了避免上述几种事务之间的影响,SQL Server通过设置不同的隔离等级来进行不同程度的避免。因为高的隔离等级意味着更多的锁。
SQL Server提供了5种选项来避免不同级别的事务之间的影响

隔离等级由低到高分别为

  • Read Uncommited(最高的性能,但可能出现脏读,不可重复读,幻读)
  • Read commited(可能出现不可重复读,幻读)
  • Repeatable Read(可能出现幻读)
  • Serializable(最低的性能,一次只能执行一个事务,但避免了上述所有情况)
  • SNOPSHOT(这个是通过在tempDB中创建一个额外的副本来避免脏读,不可重复读,会给tempDB造成额外负担)

理解持久性(Durability):

持久性,意味着事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

SQL SERVER通过write-ahead transaction log来保证持久性。write-ahead transaction log的意思是,事务中对数据库的改变在写入到数据库之前,首先写入到事务日志中。而事务日志是按照顺序排号的(LSN)。当数据库崩溃或者

REFERENCE

CareySon. "浅谈SQL SERVER中事务的ACID", 博客园, 2012