MySQL InnoDB存储引擎:事务实现

版权声明:本文为博主原创文章,转载请注明作者与出处,http://blog.csdn.net/lixingtao0520 https://blog.csdn.net/lixingtao0520/article/details/83869099

事务基础知识

1、事务ACID特性:

    Atomic(原子性): 事务要么成功,要么失败。

    Consistency(一致性): 事务会把数据库从一种一致状态转换为另一种一致状态。

     Isolation(隔离性): 事务之间相互隔离,互不影响。

    Durability(持久性): 事务一旦提交,结果是永久性的。

2、数据库事务的隔离级别有4个。由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable。

3、并发事务带来的三个问题。

    (1)脏读

        事务A读取L行记录值为1,未提交。同时,事务B更改了L行记录为2,且也未提交。事务A再次读取L行记录值时,读取出来的数据为2。则表明产生的“脏读”,因为事务A读取了事务B未提交的数据(事务B可能回滚)。

    (2)不可重复读

        事务A读取L行记录值为1,未提交。同时,事务B更改了L行记录为2,已提交。事务A再次读取L行记录值时,读取出来的数据为2,即同一事务,两次读取同一数据的结果不一致,表明产生了“不可重复读”。

    (3)幻读

        加入表中只有一行数据,id =1,事务A读取表中大于1的数据,返回结果集为空,未提交。同时,事务B向表中插入了一条数据,id =2,提交。如果事务A再向表中插入id =2的记录,此时会报错,不能插入重复数据。对于事务A来说,明明大于1的记录为空,但不能插入值为2的数据,表明产生了“幻读”。

MySQL InnoDB存储引擎中的事务

1、MySQL InnoDB存储引擎中的锁。

  InnoDB存储引擎实现了两种行级锁:S Lock(共享锁) 和X Lock(排他锁)。如果一个事务对某行记录加上了共享锁,那么其他事务也可以获得此行记录上的共享锁,但是会阻塞排他锁。

2、一致性非锁定读和一致性锁定读。

    一致性非锁定读:指InnoDB存储引擎通过多版本控制的方式来获取当前时间数据库中的行数据。也就是说如果读取的行记录正在被修改,那么读取操作不会等待行数据上锁的释放,而是读取行数据的一个快照数据。

在默认设置(Repeatable read)下,InnoDB存储引擎select * from 语句走的是一致性非锁定读。但是并不是每个事物隔离级别下都采用一致性非锁定读。哪些隔离级别下不读快照数据呢?read uncommit和serializable。即时当前事物隔离级别使用一致性非锁定读,那么读取的快照数据也可能不一样,因为一个行记录可能有多个快照版本,由此带来的并发问题成为 多版本并发控制(Multi Version Concurrency Control,MVCC)。事务隔离级别Read committed下,非锁定读总是读取被锁定行的最新一份快照数据;而在Repeatable read下,一致性非锁定读总是读取事务开始时的行数据版本。

    一致性锁定读:InnoDB对于Select支持两种一致性锁定读。select 。。。for update;select。。。lock in share mode.前者是对行数据加排它锁,后者是加共享锁。

3、InnoDB存储引擎有3种行锁的算法。

    Record Lock:单个行记录上的锁。

    Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。

    Next-Key Lock:Gap Lock+Record Lock,锁定一个范围,并锁定记录本身。

    在Repeatable Read隔离级别下,InnoDB对于行的查询都是采用Next-Key Lock锁定算法。当时如果查询的索引含有唯一属性,InnoDB会对Next-Key Lock进行优化,将其降级为Record Lock,即仅锁定索引本身,而不是范围。Next-Key Lock算法正是为了解决“幻读”问题。

    Record Lock 在锁定时,总是会锁住索引记录。

    可以通过设置隔离级别为Read Commited和配置参数来关闭gap Lock,此时除了外键约束和唯一性检查依然需要Gap Lock外,其他仅使用Record Lock进行锁定。

4、MySQL InnoDB存储引擎中的事务

   InnoDB存储引擎中,事务的隔离性是通过锁来实现的。redo Log(重做日志)用来保证事务的原子性和持久性,事务的一致性是通过undo log来实现。redo log恢复提交事务修改的页操作,undo log回滚行记录到某个特定版本。

5、redo log 重做日志包括两部分:1 是内存中的重做日志缓冲 ;2 是重做日志文件。在事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化,待事务commit操作完成才算完成。

     在每次事务提交之前,将重做日志写入缓冲,为了持久化重做日志,存储引擎需要调用一次fsync操作,同步缓冲到重做日志文件中。允许设置重做日志缓冲的刷新为定时刷新,而不是每一次事务提交都刷新到文件中,来提高数据库性能。 

6、undo log 。当用户执行的事务失败了,需要请求回滚时,就可以利用undo log来讲数据回滚到修改之前。undo log是存放在数据库内部的一个特殊段(segemnt)。undo 除了回滚使用外,MVCC的实现也是通过undo来完成,用读取一行记录时,如果该记录已经被锁,则当前事务可以通过undo读取之前的行版本信息,来实现非锁定读。undo log也会产生redo log。

    undo log所在的页在事务提交后,可以重用。但事务提交后并不能马上删除undo log及 undo log所在的页,可能有其他事务通过undo log来得到行记录之前的版本。是否能删除,是由purge线程来判断。

参考:

《MySQL技术内幕:InnoDB存储引擎》

猜你喜欢

转载自blog.csdn.net/lixingtao0520/article/details/83869099