REPEATABLE
READ解决了脏读的问题。该隔离级别保证了在同一个事务中多次读取同样记录结果是一致的。但是理论上,可重复读隔离级别还是无法解决另外一个幻读(Phantom
Read)的问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom
Row)。InnoDB和XtraDB存储引擎通过多版本并发控制(MVCC,Multiversion
Concurrency Control)解决了幻读的问题。

 

READ COMMITTED(提交读)

你肯定听说mysql的表锁和行锁,那你可能以为事务是基于行锁实现的。其实并没有那么简单,为了提高并发性能,mysql的大多是事务引擎都同时实现了多版本并发控制(MVCC)。它在很多情况下避免了加锁操作,所以开销更低。MVCC大都实现了非阻塞的读操作,写操作也只锁定必要的行。

打钩说明该隔离级别还存在这种情况,打X代表该隔离级别已经解决了这种情况:

隔离级别 脏读可能性 不可重复读可能性 幻读可能性 加锁读
READ UNCOMMITTED YES YES YES NO
READ COMMITTED NO YES YES NO
REPEATABLE READ NO NO YES NO
SERIALIZABLE NO NO NO YES

隔离级别:

如果你真的实验了,会发现mysql的REPETABLE
READ隔离级别并不会出现幻读的现象。那你有没有想过mysql的事务是怎么实现的呢?

 

  • 未提交读(READ
    UNCOMMITTED):事务中的修改,即使没有提交,其他事务也可以读到,这就有可能造成了脏读。
  • 提交读(READ
    COMMITTED):大多数数据库系统默认实用的隔离级别就是这种,但mysql不是。READ COMMITTED就是在事务提交前,所做的修改对其他事务是不可见的。但READ COMMITTED可能会造成不可重复读。就是在一个事务中,同样的查询语句,可能会得到不一样的结果。其实就是在两次查询中间,另一个事务修改了查询结果的值。
  • 可重复读(REPETABLE READ):REPETABLE
    READ解决了脏读和不可重复读的问题,但理论上,REPETABLE
    READ无法解决幻读的问题。幻读就是指,一个事务在读取某一范围的值时,另一个事务恰好在该范围内插入了新纪录,那么当你再次读取该范围的值时,就会产生幻行。这与不可重复读有点像,只不过不可重复读时永利皇宫登录网址 ,UPDATE,而幻读时INSERT
  • 可串行化(SERIALIZABLE):SERIALIZABLE读取每一行数据都要加锁,强制事务串行执行,所以可能导致大量的超时和锁争用问题。

作者:陆炫志

出处:xuanzhi的博客 http://www.cnblogs.com/xuanzhi201111

您的支持是对博主最大的鼓励,感谢您的认真阅读。本文版权归作者所有,欢迎转载,但请保留该声明。

银行应用是解释事务的一个经典例子。假设一个银行的数据库有两张表:支票(checking)和储蓄(savings)表。现在johnson要从支票账户中转移200块大洋到储蓄表中,那么至少需要三个步骤:

 

  • SELECT查询出的数据需要满足2个条件    1、创建版本号 <= 系统版本号 
    2、删除版本号为空或删除版本号>系统版本号
  • INSERT     为新插入的每一行保存当前事务版本号为行的创建版本号
  • UPDATE  为插入的一行新记录保存当前事务版本号为行的创建版本号,同时保存当前事务版本号为原来的行的删除版本号
  • DELETE  为删除的每一行保存当前事务版本号为行的删除版本号

  SERIALIZABLE是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。简单来说,SERIALIZABLE会在读取每一行数据都加锁,所以可能导致大量的超时和锁争用问题。实际应用中也很少用到这个隔离级别,只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。

细心的人可能会注意到。在讨论隔离性的时候,我用了“通常来说”,下面就让我们讨论下事务的隔离级别。

    
通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。(在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时有另外的一个账户汇总程序开始运行,则其看到支票帐户的余额并没有被减去200美元。)

SET session transaction isolation level read committed;

上述三个步骤的操作必须打包在一个事务中,任何一个步骤失败,则必须回滚所有的步骤。

事务之所以可靠,当然离不开ACID特性:

隔离性(isolation)

试想一下,如果上面步骤执行到第二步,突然因为什么原因而终止了,顾客支票账户中莫名其妙的减少了200块大洋。如果顾客恰好是一位情绪激动的大妈,那你就等着大妈带着平底锅和四级头去银行找你吧!

READ UNCOMMITTED(未提交读)

  • 原子性(atomicity):整个事务中的操作要么全部成功,要么全部失败。
  • 一致性(consistency):数据库总是从一个一致性状态转换到另一个一致性状态。比如上面所说的,事务开始前和执行后,顾客johnson在银行的总账户余额是一样的。
  • 隔离性(isolation):通常来说,一个事务所做的修改在提交之前,其他事务是不可见的。也就是说事务间是相互隔离的。
  • 持久性(durability):事务在提交之后,对数据库数据所做的修改是永久性的。

  大多数数据库系统的默认隔离级别都是READ COMMTTED(但MySQL不是)。READ
COMMITTED满足前面提到的隔离性的简单定义:一个事务开始时,只能”看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。这个级别有时候叫做不可重复读(nonrepeatble
read),因为两次执行同样的查询,可能会得到不一样的结果

  1. START TRANSACTION;
  2. SELECT balance FROM checking WHERE customer_id=123456;
  3. UPDATE checking SET balance = balance – 200 WHERE
    customer_id=123456;
  4. UPDATE savings SET balance = balance + 200 WHERE
    customer_id=123456;
  5. COMMIT;

    
数据库总是从一个一致性的状态转换到另一个一致性的状态。(在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。)

最近买了《高性能MySQL》这本书回来看,从中收益颇多!我来一吐为快!

ACID表示原子性(atomicity)、一致性(consistency)、隔离性(isolation)和持久性(durability)。一个很好的事务处理系统,必须具备这些标准特性:

  1. 检查支票账户余额是否高于200块大洋
  2. 支票账户减少200块大洋
  3. 储蓄账户中增加200块大洋

SERIALIZABLE(可串行化)

到这里,如果还不是太懂,你需要细细消化下前面的内容,这时可以打开mysql,将隔离级别设置为READ
COMMITTED。然后试试它是不是解决了脏读,会不会出现不可重复读?再将隔离级别设置为REPETABLE
READ。看看REPETABLE READ是不是解决了不可重复读,会不会出现幻读?

  在READ
UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读(Dirty
Read)。这个级别会导致很多问题,从性能上来说,READ
UNCOMMITTED不会比其他的级别好太多,但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。

个人建议,除非你明确知道自己在干什么,否则轻易不要显式加锁,只会事倍功半!!!

网站地图xml地图