zoukankan      html  css  js  c++  java
  • 事务隔离

    引自:http://blog.csdn.net/turkeyzhou/article/details/7636165

    1      什么是事务

    1.1 我们为什么需要事务

    数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关 操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、 一致性、隔离性和持久性)属性。

    上面的解释和描述来自百度百科(http://baike.baidu.com/view/1298364.htm),我们为什么需要事务,通俗点说,就是需要“一组操作或者行为,要么全成功,要么全失败,一荣俱荣,一辱俱辱”。     

    1.2 事务ACID属性

    事务的特性可以定义为四种属性:ACID(atomicity,consistency,isolation,durability)。

    l   atomicity:原子性,在一个事务中的所有操作,相当于一个原子操作,要么全部成功,要么全部失败。

    l   consistency:一致性,就是在事务执行前后,对于事务本身的用意而言,数据库中的数据是保持一致的,数据库的一致性是建立在原子性的基础之上的,更多的由编码的程序员保证,最经典的案例是A,B帐号之间的转账。

    在整个过程中,对于一致性的定义是AB的账户总额保持事务前后一致,而次数是通过事务的原子性以及事务定义的编码共同来实现的(如果你本意是转账,A减去50而B加上100则不符合一致性本意)。

    另一方面则表示,一致性状态表示只有合法的数据才能被写入数据库,如果事务执行的某些操作,违反了数据的一致性规则,则 事务会rollback到之前数据一致的状态,另一方面,如果事务执行成功,则会将数据状态从事务执行前的符合数据一致性规则的一种状态,变迁到事务执行 后的另一种数据符合一致性规则的状态。(Definition: Consistency states that only valid data will be written to thedatabase. If, for some reason, a transaction is executed that violates thedatabase’s consistency rules, the entire transaction will be rolled back andthe database will be restored to a state consistent with those rules. On theother hand, if a transaction successfully executes, it will take the databasefrom one state that is consistent with the rules to another state that is alsoconsistent with the rules.)

    l   isolation:隔离性,事务的隔离性是指事务和事务之间的数据可见性,这也是本文需要详细介绍的地方。数据库定义了各种隔离级别,以在并发性和数据完整性中权衡。

    l   durability:持久性,事务完成以后,所有的数据都将持久到数据库中,不会因为其他原因而丢失。

     

    2      事务隔离

    2.1       事务同时读写所带来的问题

    事务的隔离性是指当多个事务并发同时执行的时候,数据的可见性不同而导致的一些问题,主要问题包括如下四种:

    l   更新丢失(同时更新);

    当两个事务同时对一条数据进行更新的时候,因为执行顺序交叉,在没有协同的情况,可能导致某一个事务的更新被覆盖,我们称之为更新丢失(这在银行转账中是十分危险和不可接受的)。

    l   脏读;

    顾名思义,脏读,未提交读,均是指事务在同事读写的过程中间,一个事务读取到另一个事务没有commit的更新,此时,这个更新是否会被正式提交,或者发生异常回滚是不可预料的,所以可以认定此时所读取到的数据为脏数据。

     

    l   不可重复读

    不可重复读取主要是因为在一次事务中多次读取某条记录,但因为其他事务的介入,而导致多次读取的值不一致。

    l   幻读;

    幻读主要在事务A中读取记录数为N条,而事务B插入一条,则事务A再次读取时则变成了N+1条。

    3      数据库锁

    3.1       锁的类型

    如同线程一样,数据库也用锁来保证事务之间的协同工作,在数据库中,锁分为共享锁和排他锁,顾名思义,多个共享锁可以共存,而排它锁则是独占锁,共享锁也称之为读锁,而排它锁也称之为独占锁,写锁。

    l  排他锁 被加锁的对象只能被持有锁的事务读取和修改,其他事务无法在该对象上加其他锁,也不能读取和修改该对象

    l  共享锁 被加锁的对象可以被持锁事务读取,但是不能被修改,其他事务也可以在上面再加共享锁。

     

    特别的,对共享锁: 如果两个事务对同一个资源上了共享锁,事务A 想更新该数据,那么它必须等待 事务B 释放其共享锁。

    3.2       锁粒度

    锁的范围和粒度可以分为表锁和行锁,其中表锁为数据库实现,而行锁则由存储引擎实现(如innodb引擎)。

    3.3       封锁协议(Locking Protocol)

    在运用锁来进行事务之间的协议时,还必须基于一定的规则,如何时加锁,何时释放锁,加锁的粒度以及等等。这些称之为封锁协议,不同的封锁协议定义了不同的隔离级别。不同的隔离级别则解决了之前事务协作锁带来的问题,以便服务在吞吐量和并发性以及事务完整性之间做出权衡。

    4      事务隔离级别

    针对事务协作锁带来的四大问题,于是根据不同的封锁协议,制定了事务间的隔离级别。其实本质上均是通过锁来干涉事务之间的执行顺序。

    4.1       事务协作问题原因极其分析

    l   丢失更新

    原因:读锁可以共享,而记录常驻内存。

    解决方式:读锁升级为独占锁,或者重复读取,cas更新。

    l   脏读

    执行场景(顺序):事务A在事务B更新数据和回滚过程中间读取记录。

    解决方式:当事务B更新数据的时候禁止其他事务对记录进行读取。

    加锁方式:事务B将写锁(独占锁)保持到事务结束。

    l   不可重复读

    执行场景(顺序):事务A第一次读取数据在事务B更新数据并提交之前,第二次读取数据在事务B更新记录并提交之后,导致同一次事务中多次读取同一记录不同。

        解决方式:事务A在读取数据和提交事务之间不允许其他事务对数据进行修改。

        加锁方式:事务A持有共享锁直至事务结束。

    l   幻读

    解决方式:数据库将行锁升级为表锁;

    4.2       隔离级别及对应封锁规则

    l  read uncommitted(一级封锁规则)

    表示可以接受读取未提交的数据(脏读)。封锁规则为:当事务修改记录时,为记录添加共享锁直至事务结束,在次过程中,其他事务可以读取和更新数据。因此此种隔离级别会带来丢失更新,脏读,重复读,幻读各种问题。

    l  read commited(二次封锁规则)

    表示允许读取提交后的数据,意思是允许(不可重复读)现象,但拒绝脏读。

    封锁规则为对应的脏读解决方案,事务将写锁(独占锁)保持到事务结束,而读取数据的时候当读取操作完毕则立即释放读锁。

    执行顺序会变成:


    l  repeatable read(三级封锁协议)

    表示可以重复读(意思为不允许不可重复读,真纠结)。封锁规则为,保持共享锁到事务结束。

    但因为是行锁,无法避免幻读,另外因为事务读锁可以并存,那是否repeatable read在应对丢失更新的情况方面表现如何呢?

    你会发现,因为共享锁和排他锁的释放周期均被放大,导致了资源的死锁,数据库如何解决这种死锁状况呢?如SQL Server在处理这种情况时则是引入了Update锁,当读取数据的时候为记录上获取Update锁,哪个事务先修改,则将锁升级为独占锁从而对该数据 进行修改。而mysql innodb则主要是通过两方面来处理死锁问题:

    n   死锁检测;当发现死锁时,将一个事务回退(回滚拥有最少排他行级锁的事务,一种对最易回滚事务的大致估算),令一个事务获得锁完成事务,但是innodb也无法检测所有死锁的问题。

    n   死锁超时;可以通过设置innodb_lock_wait_timeout来设置获取锁而等待的超时时间。

    l  Serialization(四级封锁)

    直接对 事务中 所 读取 或者 更改的数据所在的表加表锁,也就是说,其他事务不能 读写 该表中的任何数据。这样所有的 脏读,不可重复读,幻读 ,都得以避免。

    5      MySql事务隔离级别设置

    在mysql中,可以通过如下命令查询当前事务隔离级别:

                        SELECT@@global.tx_isolation;  //全局        

                        SELECT@@tx_isolation;//当前会话

    设置会话级别分别为:

    setglobal transaction isolation level read committed;

    setsession transaction isolation level read committed;

  • 相关阅读:
    【C#】.net 发送get/post请求
    【C#】什么时候使用virtual什么时候使用abstract
    【C#】为什么有可能会被多个线程修改的对象要加线程锁
    【ADO.NET】 使用通用数据库操作类Database (SQL Server)
    【ADO.NET】 基础 (SQL Server)
    【前端】模拟微信上传图片(带预览,支持预览gif)
    【前端】Html5浏览器缓存 sessionStorage 与 localStorage
    【C#】.net 导出Excel功能
    【前端】jQurey Plugin
    【c#】对象转json字符串/字符串转Json对象
  • 原文地址:https://www.cnblogs.com/nearpengju123/p/4914978.html
Copyright © 2011-2022 走看看