栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

InnoDB的事务和崩溃恢复

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

InnoDB的事务和崩溃恢复

欢迎访问原文地址来阅读最新版本
转载请注明出处:http://kang.fun/innodb-transaction

事务隔离级别 1. Read uncommitted

读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。

那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。

2. Read committed

读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

那怎么解决可能的不可重复读问题?Repeatable read !

3. Repeatable read(Mysql默认)

重复读,就是在开始读取数据(事务开启)时,不再允许修改操作,但允许写操作。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

什么时候会出现幻读?

事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。

4. Serializable 序列化

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

如何保证事务 - ACID

为保证事务(transaction)是正确可靠的,数据库引擎必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。

InnoDB分别使用如下方式来保证了这四个特性:

redo log重做日志用来保证事务的持久性undo log回滚日志保证事务的原子性undo log + redo log保证事务的一致性锁(共享、排他)用来保证事务的隔离性 三种log的作用 1. binlog

binlog是Mysql Server层级的逻辑变更日志,它记录了数据库的所有变更,以二进制存储在磁盘上。

主要作用在两个方面:

增量备份

主从复制

2. redo log

redo log是InnoDB存储引擎层的日志,记录的是新数据的备份,在事务提交前将redo log持久化。

数据写入时,实际上是写入了内存中的Buffer Pool,Buffer Pool中的数据根据策略定期写入磁盘。那么就带来一个问题,如果在写入磁盘前系统崩溃了,数据一致性难以保证,所以在事务完成前会写入redo log,系统崩溃重启后,通过redo log来恢复未持久化到页中的数据。

这样还能使写入变为一个异步操作,那么在写入磁盘前,数据库引擎还能对多次同一个键的修改进行合并,降低磁盘写入内容和次数。

3. undo log

事务中的每一次修改,innodb 都会先记录对应的 undo log 记录。与 redo log 用于数据的灾后重新提交不同,undo log 主要用于数据修改的回滚。

与 redo log 记录的是物理页的修改不同,undo log 记录的是逻辑日志。

在事务中每次更新记录后,都会将旧值放到一条undo日志中,就算是该记录的一个旧版本,随着更新次数的增多,所有的版本都会被数据的roll_pointer属性连接成一个链表,我们把这个链表称之为版本链,版本链的头节点就是当前记录最新的值。

当事务回滚时,通过undo log对数据反向更新。

InnoDB保证事务隔离性的方式 - MVCC(多版本并发控制)

多版本的意思就是一条数据在数据库中同时存在多个版本,在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本id,比对事务id并根据事务隔离级别去判断读取哪个版本的数据。

隐藏属性是否必须描述
row_id行ID,唯一标识一条记录(如果定义主键,则没有)
transaction_id事务ID
roll_pointerDB_ROLL_PTR是一个回滚指针,用于配合undo日志,指向上一个旧版本,形成版本链
事务持久化策略 1. steal / no-steal

是否允许一个uncommitted的事务将修改更新到磁盘

steal策略

那么此时磁盘上就可能包含uncommitted的数据,因此系统需要记录undo log,以防事务abort时进行回滚(roll-back)

no steal策略

就表示磁盘上不会存在uncommitted数据,因此无需回滚操作,也就无需记录undo log

2. force / no-force

事务在committed之后是否将所有更新立刻持久化到磁盘

force策略

在committed之后必须将所有更新立刻持久化到磁盘

no-force策略

在committed之后可以不立即持久化到磁盘,而是缓存更新批量持久化到磁盘

no-force的优点是提升顺序写,缺点是有可能在crash后导致事务数据丢失,所以需要记录redo log,系统重启后进行前滚(roll-forward)操作

现在DBMS常用的是steal/no-force策略,因此一般都需要记录redo log和undo log。这样可以获得较快的运行时性能,代价就是在数据库恢复(recovery)的时候需要做很多的事情,增大了系统重启的时间。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/778777.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号