高性能MySQL学习笔记(4) —— 事务隔离级别

事务隔离级别

  事务的ACID属性中的隔离性,如何实现呢?在SQL标准中定义了四种隔离级别。
  但要注意,标准中定义的这四个级别,在实际上各个存储引擎的实现是不尽相同的,有些细节地方还是不一样的,学习的时候需要注意下。
  有关事务的ACID属性详见:数据库事务。

并发问题

  在说明事务隔离级别之前,先说说事务并发可能引发的问题。
  1、更新丢失:一个事务的更新覆盖了另一个事务的更新。事务A:向银行卡存钱100元。事务B:向银行卡存钱200元。A和B同时读到银行卡的余额,分别更新余额,后提交的事务B覆盖了事务A的更新,这样无形中就损失了100元。

  2、脏读:一个事务读取了另一个事务未提交的数据。事务A:张三妻子给张三转账100元。事务B:张三查询余额。事务A转账后(还未提交),事务B查询多了100元。事务A由于某种问题,比如超时,进行回滚,这个时候事务B查询到的数据是假数据。(防止不了select操作)

  3、不可重复读:一个事务两次读取同一个数据,两次读取的数据不一致。事务A:张三妻子给张三转账100元。事务B:张三两次查询余额。事务B第一次查询余额,事务A还没有转账,第二次查询余额,事务A已经转账了,导致一个事务中,两次读取同一个数据,读取的数据不一致。(防止不了update操作)

  4、幻象读:一个事务两次读取一个范围的记录,两次读取的记录数不一致。事务A:张三妻子两次查询张三有几张银行卡。事务B:张三新办一张银行卡。事务A第一次查询银行卡数的时候,张三还没有新办银行卡,第二次查询银行卡数的时候,张三已经新办了一张银行卡,导致两次读取的银行卡数不一样。(防止不了insert/delete操作)

隔离级别

  事务的隔离级别和数据库并发性是对立的,两者此增彼长。以下隔离级别程度由低到高,并发性也就从高到低。隔离级别的设置是根据解决以上问题而依次设立的。

1.未提交读

  Read uncommited:如果一个事务已经开始修改数据,则另外一个事务不允许同时进行修改操作,但允许其他事务读此行数据,即事务中的修改,即使没有提交,对其他的事务也是可见的,也就是说其他事务不可修改但可以读取该事务未提交的数据,这种级别解决了更新丢失问题,但第2、3、4种问题都会出现,最不安全,一般不予采用。
  可以这样理解:未提交读是把事务每一步结果写到了数据库中,这个时候别的事务不能修改但可以“看到”,从而取到了“脏数据”。一般情况下,中间结果是不能直接写到数据库中被其他事务看到的。
总结:该级别防止了一个事务修改数据的同时另一个事务修改(对同一数据,下同),没防止修改的同时读(即仅对修改加了共享锁)。

2.提交读

  Read commited:事务结束之前,未提交之前,其他事务看到的数据是未执行该事务的值,即事务所做的任何修改对其他事务是不可见的,这个事务也叫不可重复读(nonrepeatable read),是大多数数据库系统默认的隔离级别(但MySQL不是)。

//事务A
{
    1:访问x   //1
    2:访问x   //2
}
//事务B
{
    修改x    //3
}

  两个事务同时执行,顺序为:132,出现前后两次访问x值不同问题。(这里的3不是中间结果,是已提交结果。)
  不可重复读解决了更新丢失、脏读,但不能解决不可重复读和幻读问题。
总结:该级别防止了一个事务修改的同时另一个事务修改,也防止修改的同时读,但没防止读的时候修改(即仅对修改加了排它锁)。

3.可重复读

  Repeatable read,MySQL默认隔离级别,可以解决以上第1、2、3问题,但不能解决“幻读”问题,可重复读的做法是:读哪几行记录时候,加锁,这样其他事务就不能修改了,多次读的数据当然就一样了,但是,假如这个时候有新增操作,新增的数据符合读的条件,再次读就会多出条数据,对于这个事务来说就好像出现了幻觉,就是所谓的“幻读”。
总结:该级别防止了一个事务修改的同时另一个事务修改,也防止修改的同时读,也防止读的时候修改,但没防止读的时候新增/删除(对影响的数据行的修改、读加了排它锁,没对表进行加锁,解决幻读,不一定要对表加锁,即隔离级别变为4,也可以通过MVCC解决)。

4.可串行化

  Serializable,最高的隔离级别,所有事务串行执行,这样不能并发,当然就没有并发所带来的问题,这是一种极端做法,实际应用很少用到,只有在非常需要数据一致性且可以接受无并发的情况下采用。
总结:表加锁。

总结

  以上四个级别依次解决的问题的实质:修改时候同时修改、修改的时候同时读、读的时候同时修改、读的时候同时新增/删除。

你可能感兴趣的:(事务隔离级别,更新丢失,脏读,不可重复读,幻读,MySQL)