Mysql四种事务隔离级别实现

事务四个基本特性实现

事务具有原子性、一致性、隔离性和持久性。不同事务的实现所对应四个特性的实现方式略有不同。
Mysql四种事务隔离级别实现_第1张图片

原子性实现

事务是并发控制的最小单位,如果无法保证原子性,就无法保证一个事务的所有操作都被执行完成。原子性是通过事务回滚机制保证,undo log实现了事务回滚。
Mysql四种事务隔离级别实现_第2张图片
在执行update/delete/insert跟更新操作时,会对应生成update/insert/delete相反的更新undo log日志,在部分事务执行失败的时候,使用undo log日志将已经执行的更新操作回滚,保证了事务的原子性。

持久性实现

持久性是指已经更新的操作会被记录在磁盘上,即使机器宕机,更新结果也依然不会丢失。
问题引出:

MySQL数据存储在磁盘上,频繁读取I/O效率低,所以一般会在加一层缓冲区,通过缓冲区读取数据过程:

读数据:先尝试从缓冲区读取数据,缓冲区数据不存在,从磁盘读数据,并将读到的数据更新到缓冲区。
写数据:先将数据写入到缓冲区,缓冲区的数据定时刷新到磁盘中。

使用缓冲区写数据时,由于数据不是实时写入到磁盘,在更新的数据没有刷新到磁盘期间宕机会造成数据丢失,mysql使用了redo log解决该问题。redo log日志记录了所有更新操作,每更新一条记录,都会生成一个redo log日志,并将redo log日志写入磁盘,redo生成过程。
Mysql四种事务隔离级别实现_第3张图片
mysql 写盘有两个buffer,第一个时mysql 自己设置的log buffer,另外一个时os和磁盘间buffer,可以通过innodb_flush_log_at_trx_commit设置redo log刷盘时间。

值为0:每秒调用flush命令将redo log从log buffer 写到os_cache,同时调用fsync()将os_cache的redo log刷新到磁盘中;

值为1:默认,每次事务提交后都将redo log 写入log buffer,然后同步刷新到磁盘;

值为2,每次事务提交后都将redo log写入到 log buffer 中,然后每隔一秒将os_cache中redo log写入到磁盘中。值为1和值为2,宕机都有可能造成数据丢失不能回复

虽然redo log也需要写盘,有IO消耗,数据刷新以页为单位,每个页默认大小为16kb,即使页中跟新非常少的数据,也需要将这个页写回磁盘,redo log 只记录更新的日志,需要刷盘的数据更小

redo log主要用于机器宕机数据恢复,回复过程由mysql自动执行,bin log可以基于某个时间点对数据进行恢复,同时,bin log也用于主从复制。

隔离性

隔离性主要是指两个事务并行执行,彼此之间相互干扰。最高级别的隔离是串行化。锁+MVCC(读快照)是实现事务隔离级。

锁:控制实现一个事务写操作对其他事务写操作的影响,防止写覆盖。

MVCC(读快照):控制一个事务写操作对其它事务读操作影响。

首先需要明确,在RU、RC和RR隔离级别下,所有更新操作都会隐式枷锁,加锁解决了写覆盖。

在并发读取表中数据时,可能会出现脏读、不可重读和幻读三种情况。

脏读:读了别人没有提交的数据。

不可重复读:指读取同一条数据,前后数据不一致,由update引起。

幻读:读取一个范围内的数据,读取的数量不一致,由insert/update组成。

通过设置不同的隔离级别可以避免不安全读情况的发生,根据自己的应用场景选择不同隔离级别。

√:表示可能发生,X:表示能够避免

脏读 不可重复读 幻读
读为提交
读已提交 x
可重复读 x x
串行化 x x x

MVCC只在RC和RR级别工作,在RU情况的下读模式是当前读,不会创建快照信息,在searial模式下时对所有读取的行枷锁。在RC和RR模式下,读是快照读( select… in share modehe 和select …for udapte时当前读,除外),update/delete和insert都是当前读。

MVCC实现原理:https://blog.csdn.net/huhu123444/article/details/122036671

一致性

原子性、持久性和隔离性合起来共同保证了一致性,也是事务要达到的目标,修改之间满足各种约束的,修改之后也依然满足各种约束,业务上从一个A账户转账到B账户,最终应该保证A扣除金额和B增加金额相等。

读未提交(read uncommited)实现

执行当前读,读取数据的最新记录。除了读未提交隔离别下,select 操作时执行当前读,执行当前读的语句还有(RU、RC和RR都是):

1 update ...
2 insert ...
3 delete...
4 select ... for update /lock in share mode。

因为要对数据进行更新,所以要获得元素最新值。

读已提交(read commited)实现

在执行查询时,根据生成的read view中的所有活跃事务id和undo log链中每条记录事务版本号进行比较,判断数据可见性。

MVCC实现读已提交:https://blog.csdn.net/huhu123444/article/details/122036671

可重复读(read repeatable)实现

RC级别下,每次查询数据会生成一个新的readView,所以无法保证可重复读。RR级别下,除了使用MVCC,在创建事务的时候,使用trx_assign_read_view函数会创建一个global read view,每次查询都使用同一个read view,保证了可重复读。可见性判断规则和RC级别一样。

MVCC实现可重复读:https://blog.csdn.net/huhu123444/article/details/122036671

串行化(Searial)实现

在读取数据时,对整个表加共享锁;在执行更细操作时,对整个表加排他锁。

你可能感兴趣的:(mysql,数据库,mvcc,dba)