数据库的事务有四大特性:原子性、隔离性、一致性、持久型,以下为具体实现方式..
【原子性】
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
原子性的实现需要用到undo日志了。重做,主要记录了事务的行为,可以很好地通过对其页进行重做,如果数据库事务发生了回滚,需要用undo日志将数据库回滚到修改之前的样子。
Undo日志通过存储数据库修改的逻辑日志来恢复数据库,比如在进行回滚的时候,对于insert,innodb会进行delete操作,对于delete会进行inert,对于update会执行一个相反的update将之前的数据放回去
Undo的另一个作用是MVCC,MVCC的实现是通过undo来完成的,当用户读取一条记录的时候,若该记录已经被其他的事务占用,当前事务可以通过undo读取到之前的行版本信息,通过此来实现非锁定读取
【隔离性】
隔离性是当多个用户并发访问数据库的时候,比如操作同一张表时,数据库会为每一个用户开启的事务,不能被其他的事务操作所干扰,多个并发事务之间要进行互相隔离。
Innodb中要想访问某一行记录的话,首先需要获取到他的锁,之后才能继续进行访问,通过锁,可以很好的实现事务的隔离性,innodb默认访问的级别是Read Repeatable(可重复读),避免了脏读,不可重复读等特性,并且在行锁的基础上又加上了间隙锁来解决幻读的问题。
锁带来的数据库的性能瓶颈(读写冲突)可以通过MVCC实现。主要是通过每行记录后面的隐藏列来实现的。两个列保存了行的创建时间和过期时间(或删除时间). 这里的事件就是事务的Id,每个事务都有一个Id,Id是自增的. 下面来看一下主要是如何操作的:
select 会查找行记录的创建时间早于当前事务Id的行,或者说删除时间那一列Id大于自己的Id的行记录
insert 插入一条新的数据,并保存当前事务Id作为记录的创建时间.
delete 为删除的每一行保存当前事务Id为行删除标识
update 插入一条新的记录,并且把当前事务Id保存到新的行记录中,并设置旧的行记录的删除标识为此事务Id.
MVCC只在Repeatable Read和Read Commited两个隔离级别下工作,其他情况下都不兼容.因为Read UnCommited总是读取最新的行,而Serializable总是会对所有读取的行都加锁.
【一致性】
一致性是指事务必须使数据库从一个一致性的状态转换到另一个一致性的状态,也就是说一个事务执行之前和执行之后都必须保持一致性的状态。
每个事务都是互相隔离的,那么最终数据肯定也是一致性的,因为每个事务之间都相互不影响,并且事务具备原子性。
【持久性】
持久性是事务一旦提交了,那么对数据库中的数据的改变就是永久性的,即便在数据库系统遇到故障的情况也不会丢失提交的事务的操作
Innodb的数据都是存在磁盘上的,由于磁盘太慢,所以innodb提供了缓存(buffer pool)
Buffer pool中包含了磁盘中部分页的映射,在访问数据库的时候会先去缓存池中进行访问,如果没有就把数据页读到缓冲池,在写入的时候也是要先写入bufferpool,并且bufferpool的数据会定期刷新到磁盘上。但是如果数据库突然宕机的时候,没有刷回磁盘的数据就会丢失
Redo日志保存了对数据库的修改,并且redo日志是物理格式的,即记录是对某个页的修改而不是具体的SQL语句,并且redo日志是预写式日志,所有的修改都会先写入redo日志在更新进bufferpool中。
,如果redo日志是直接向磁盘进行写入的话,不免操作也会变慢很多,因此InnoDB也引入了redo log buffer,redo日志是会先写入redo log buffer中,之后再在一定的条件下刷新会磁盘.
Master Thread每秒执行一次刷新操作,刷新回磁盘
每个事务提交的时候,会刷新回磁盘
当缓冲区的可用空间少于一半的时候,重做日志被刷新会磁盘.
为什么把redo日志写入磁盘就会比把真正的数据写入磁盘快呢,这是因为
刷新脏页的IO是随机IO,因为每次修改的数据位置随机,但是redo是顺序IO,是顺序写入的.因此会快一点
刷新脏页是以数据页为单位的,mysql默认大小是16k,在页上的每一次小的改动都要将整个页写入磁盘,而redo log只是写入真正写入的数据,无效IO大大减少.
本文详细探讨了MySQL InnoDB存储引擎在实现事务的四大特性——原子性、隔离性、一致性和持久性方面的方法。通过undo日志保证原子性,使用锁和MVCC实现隔离性,确保事务前后数据库状态的一致性,并通过redo日志和buffer pool确保持久性,即使在系统故障下也能保持数据完整性。
299

被折叠的 条评论
为什么被折叠?



