MySQL InnoDB如何保证事务特性


MySQL InnoDB如何保证事务特性

文章插图
 
 
【MySQL InnoDB如何保证事务特性】欢迎关注头条号:JAVA小野猫
如果有人问你“数据库事务有哪些特性”?你可能会很快回答出原子性、一致性、隔离性、持久性即ACID特性 。那么你知道InnoDB如何保证这些事务特性的吗?如果知道的话这篇文章就可以直接跳过不看啦(#^.^#)
先说结论:
  • redo log重做日志用来保证事务的持久性
  • undo log回滚日志保证事务的原子性
  • undo log+redo log保证事务的一致性
  • 锁(共享、排他)用来保证事务的隔离性
重做日志 redo log
重做日志 redo log 分为两部分:一部分是内存中的重做日志缓冲(redo log buffer),是易丢失的;二部分是重做日志文件(redo log file),是持久的 。InnoDB通过Force Log at Commit机制来实现持久性,当commit时,必须先将事务的所有日志写到重做日志文件进行持久化,待commit操作完成才算完成 。
InnoDB在下面情况下会将重做日志缓冲的内容写入重做日志文件:
  • master thread 每一秒将重做日志缓冲刷新到重做日志文件;
  • 每个事务提交时
  • 当重做日志缓冲池剩余空间小于1/2时
为了确保每次日志都写入重做日志文件,在每次将日志缓冲写入重做日志文件后,InnoDB存储引擎都需要调用一次fsync(刷盘)操作 。但这也不是绝对的 。用户可以通过修改innodb_flush_log_at_trx_commoit参数来控制重做日志刷新到磁盘的策略,这个可以作为大量事务提交时的优化点 。
  • 1参数默认值,表示事务提交时必须调用一次fsync操作 。
  • 0表示事务提交时,重做日志缓存并不立即写入重做日志文件,而是随着Master Thread的间隔进行fsync操作 。
  • 2表示事务提交时将重做日志写入重做日志文件,但仅写入文件系统的缓存中,不进行fsync操作 。
  • fsync的效率取决于磁盘的性能,因此磁盘的性能决定了事务提交的性能,也就是数据库的性能 。所以如果有人问你如何优化MySQL数据库的时候别忘了有硬件这一条,让他们提升硬盘配置,换SSD固态硬盘
  • 重做日志都是以512字节进行存储的,称之为重做日志块,与磁盘扇区大小一致,这意味着重做日志的写入可以保证原子性,不需要doublewrite技术 。它有以下3个特性:
  • 重做日志是在InnoDB层产生的
  • 重做日志是物理格式日志,记录的是对每个页的修改
  • 重做日志在事务进行中不断被写入,而且是顺序写入
回滚日志 undo log
为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log),然后进行数据的修改 。如果出现了错误或者用户执行了 ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态 。
undo log实现多版本并发控制(MVCC)来辅助保证事务的隔离性 。
回滚日志不同于重做日志,它是逻辑日志,对数据库的修改都逻辑的取消了 。当事务回滚时,它实际上做的是与先前相反的工作 。对于每个INSERT,InnoDB存储引擎都会完成一个DELETE;对于每个UPDATE,InnoDB存储引擎都会执行一个相反的UPDATE 。
事务提交后并不能马上删除undo log,这是因为可能还有其他事务需要通过undo log 来得到行记录之前的版本 。故事务提交时将undo log 放入一个链表中,是否可以删除undo log 根据操作不同分以下2种情况:
  • Insert undo log: insert操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo log可以在事务提交后直接删除 。不需要进行 purge操作 。
  • update undo log:记录的是对 delete和 update操作产生的 undo log 。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除 。提交时放入undo log链表,等待 purge线程进行最后的删除 。

事务的隔离性的实现原理就是锁,因而隔离性也可以称为并发控制、锁等 。事务的隔离性要求每个读写事务的对象对其他事务的操作对象能互相分离 。再者,比如操作缓冲池中的LRU列表,删除,添加、移动LRU列表中的元素,为了保证一致性那么就要锁的介入 。
锁的类型
InnoDB主要有2种锁:行级锁,意向锁
行级锁: