InnoDB 事务

【事务的实现】

事务的实现包含4个部分:
redo :redolog保证一致性
undo :undolog和redolog一起保证原子性
purge :delete数据的安全clear
group commit : redolog的缓存合并fsync到磁盘

【隔离级别】

令人惊讶的是,大部分数据库系统都没有提供真正的隔离性,最初或许是因为系统实现者并没有真正理解这些问题。如今这些问题已经弄清楚了,但是数据库实现者在正确性和性能之间做了妥协。ISO和ANIS SQL标准制定了四种事务隔离级别的标准,但是很少有数据库厂商遵循这些标准。比如Oracle数据库就不支持READUNCOMMITTED和REPEATABLEREAD的事务隔离级别。SQL标准定义的四个隔离级别为:
READ UNCOMMITTED
READ COMMITTED
REPEATABLEREAD
SERIALIZABLE

【一致性的保证】

一致性的保证:
一致性用innodb的redolog来实现。 InnoDB是事务的存储引擎,其通过Force Log at Commit机制实现事务的持久性,即当事务提交(COMMIT)时,必须先将该事务的所有日志写人到重做日志文件 进行持久化,待事务的COMMIT操作完成才算完成。redo log用来保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能。redo log基本上都是顺序写的,在数据库运行时不需要对redo log 的文件进行读取操作。而undo log是需要进行随机读写的。为了确保每次日志都写入重做日志文件,在每次将重做日志缓冲写入重做日志文件后, InnoDB存储引擎都需要调用一-次fsync操作。由于重做日志文件打开并没有使用 o_DIRECT选项,因此重做日志缓冲先写人文件系统缓存。为了确保重做日志写人磁盘,必须进行一次fsync操作。由于fsync的效率取决于磁盘的性能,因此磁盘的性能决 定了事务提交的性能,也就是数据库的性能
非一致性提高事务提交性能:
InnoDB存储引擎允许用户手工设置非持久性的情况发生,以此提高数据库的性能。 即当事务提交时,日志不写人重做日志文件,而是等待一个时间周期后再执行fsync操 。由于并非强制在事务提交时进行一次fsync操作,显然这可以显著提高数据库的性能。但是当数据库发生宕机时,由于部分日志未刷新到磁盘,因此会丢失最后一段时间的事务。
参数 innodb_flush_log_at_trx_commit用来控制重做日志刷新到磁盘的策略。
该参数的默认值为1,表示事务提交时必须调用一次fsync操作。
还可以设置该参数的值为О和2。 0表示事务提交时不进行写人重做日志操作,这个操作仅在master thread中完成,而 在master thread中每1秒会进行-次重做日志文件的fsync操作2表示事务提交时将 重做日志写人重做日志文件,但仅写人文件系统的缓存中,不进行fsync操作。在这个 设置下,当MySQL数据库发生宕机而操作系统不发生宕机时,并不会导致事务的丢失 而当操作系统宕机时,重启数据库后会丢失未从文件系统缓存刷新到重做日志文件那部 分事务
rodolog和binlog之间的区别:
redolog是记录事务内对数据页的物理修改,所以一个事务过程中会随时写redolog。
binlog是事务提交之后记录数据行的逻辑修改,是事务提交之后才提交一次写入

【原子性的保证】

事务需要保证一个事务内所有的sql语句要么全部成功要么全部失败,在commit之前由redolog记录数据改变,undolog记录数据改变的反操作,如果最终commit失败那么需要用户执行rollback通过undolog将所有数据页的修改执行反修改操作这样能保证一起失败。这就保证了原子性

【undolog】

undolog实现mvvc的一致性非锁定读,实现事务回滚。也是类似binlog记录的某个行的操作。
undolog是单独存在数据库内部segment[段,位于共享表空间]中。按照逻辑执行反操作,这是重点,而不是直接回复成事务开始前的原来的样子。
用户通常对undo有这样的误解:undo用于将数据库物理地恢复到执行语句或事务之前的样子─-—但事实并非如此。undo是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能大不相同。这是因为在多用户并发系统中,可能会有数十、数百甚至数千个并发事务。数据库的主要任务就是协调对数据记录的并发访问。 比如,一个事务在修改当前一个页中某几 条记录,同时还有别的事务在对同--个页中另几条记录进行修改。因此,不能将--个页 回滚到事务开始的样子,因为这样会影响其他事务正在进行的工作。例如,用户执行了一个INSERT 10W条记录的事务,这个事务会导致分配g介新的段,即表空间会增大。 在用户执行ROLLBACK时,会将插人的事务进行回滚,但是表 空间的大小并不会因此而收缩。因此,当InnoDB存储引擎回滚时,它实际上做的是与先前相反的工作。 对于每个INSERT,InnoDB存储引擎会完成--个DELETE﹔对于每个 DELETE,InnoDB存储引擎会执行一个INSERT;对于每个UPDATE,InnoDB存储引 擎会执行一个相反的UPDATE,将修改前的行放回去
所以最为重要的一点是,undo log 会产生redo log,因为是执行的原逻辑的反操作,也就是undo log 的产生会伴 随着redo log 的产生,这是因为undo log也需要持久性的保护
除了回滚操作,undo的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的 实现是通过undo来完成。当用户读取-行记录时,若该记录已经被其他事务占用,当 前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取

【purge】

delete和update操作可能并不直接删除原有的数据。例如,对上一小节所产生的表t,表t上列a有聚集索引,列b上有辅助索引。 对于上述的delete操作,通过前面关 于undo log 的介绍已经知道仅是将主键列等于1的记录delete flag 设置为1,记录并没有 被删除,即记录还是存在于B树中。其次,对辅助索引上a等于1,b等于1的记录同 样没有做任何处理,甚至没有产生undo log。而真正删除这行记录的操作其实被“延 了,最终在purge操作中完成。
purge用于最终完成delete和update操作。这样设计是因为InnoDB存储引擎支持 MVCC,所以记录不能在事务提交时立即进行处理。这时其他事物可能正在引用这行, 故InnoDB存储引擎需要保存记录之前的版本。而是否可以删除该条记录通过purge来 进行判断。若该行记录已不被任何其他事务引用,那么就可以进行真正的delete操作。 可见,purge操作是清理之前的delete和 update操作,将上述操作“最终”完成。而实际执行的操作为delete操作,清理之前行记录的版本。
undolog通过history形成list,用于purge执行清理操作:
在图7-17的例子中,history list表示按照事务提交的顺序将undo log进行组织。在InnoDB存储引擎的设计中,先提交的事务总在尾端。undo page存放了undo log,由于可以重用,因此一个undo page中可能存放了多个不同事务的undo logotrx5的灰色阴影表示该undo log还被其他事务引用。在执行purge的过程中,InnoDB存储引擎首先从history list中找到第一个需要被清理的记录,这里为trx1,清理之后InnoDB存储引擎会在trxl的undo log所在的页继续寻找是否存在可以被清理的记录,这里会找到事务trx3,接着找到trx5,但是发现trx5被其他事务所引用而不能清理,故去再次去history list中查找,发现这时最尾端的记录为trx2,接着找到trx2所在的页,然后依次再把事务trx6、trx4的记录进行清理。

【purge和history影响数据写入】

全局动态参数innodb_purge_batch_size用来设置每次purge操作需要清理的undopage数量。在InnoDB1.2之前,该参数的默认值为20。而从1.2版本开始,该参数的默认值为300。通常来说,该参数设置得越大,每次回收的undo page也就越多,这样可供重用的undo page就越多,减少了磁盘存储空间与分配的开销。 不过,若该参数设置得 太大,则每次需要purge处理更多的undo page,从而导致CPU和磁盘IO过于集中于对 undo log 的处理,使性能下降。因此对该参数的调整需要由有经验的DBA来操作,并且 需要长期观察数据库的运行的状态。正如官方的MySQL数据库手册所说的,普通用户不需要调整该参数。 当InnoDB存储引擎的压力非常大时,并不能高效地进行purge操作。那么history list的长度会变得越来越长。全局动态参数innodb_max_purge_lag用来控制history list的 长度,若长度大于该参数时,其会“延缓”DML的操作。该参数默认值为0,表示不对 history list做任何限制。当大于0时,就会延缓DML的操作,其延缓的算法为:
delay的单位是毫秒。此外,需要特别注意的是, delay的对象是行,而不是安 个DML 操作。例如当一个update操作需要更新5行数据时,每行数据的操作都会被
delay,故总的延时时间为5*delay。而delay的统计会在每一次purge操作完成后,重新 进行计算。InnoDB1.2版本引入了新的全局动态参数innodb_max_purge_lag_delay,其用来控制delay的最大毫秒数。也就是当上述计算得到的delay值大于该参数时,将delay设置为innodb_max_purge_lag_delay,避免由于purge操作缓慢导致其他SQL线程出现无限制的等待。

【group commit】

redolog的两次写,需要将缓存区中的redolog buffer通过fsync写入到磁盘中,group commit将多个事务的redolog buffer合并到一次fsync操作中,减少磁盘io次数
若事务为非只读事务,则每次事务提交时需要进行一次fsync操作,以此保证重做日志都已经写入磁盘。当数据库发生宕机时,可以通过重做日志进行恢复。虽然固态硬盘的出现提高了磁盘的性能,然而磁盘的fsync性能是有限的。为了提高磁盘fsync的效率,当前数据库都提供了group commit的功能,即一次fsync可以刷新确保多个事务日志被写人文件。对于InnoDB存储引擎来说,事务提交时会进行两个阶段的操作:
1)修改内存中事务对应的信息,并且将日志写人重做日志缓冲。
2)调用fsync将确保日志都从重做日志缓冲写入磁盘。
步骤2)相对步骤1)是一个较慢的过程,这是因为存储引擎需要与磁盘打交道。 但当有事务进行这个过程时,其他事务可以进行步骤1)的操作,正在提交的事物完成 提交操作后,再次进行步骤2)时,可以将多个事务的重做日志通过一次fsync刷新到磁 盘,这样就大大地减少了磁盘的压力,从而提高了数据库的整体性能。对于写人或更新 较为频繁的操作,group commit的效果尤为明显
group commit会在开启binlog时失效,因为开启binlog则使用了二阶段提交,每个步骤都需要进行一次fsync操作才能保证上下两层数据的一致性。
1)当事务提交时InnoDB存储引擎进行prepare操作。
2)MySQL数据库上层写人二进制日志。
3) InnoDB存储引擎层将日志写人重做日志文件。
     a)修改内存中事务对应的信息,并且将日志写人重做日志缓冲。
     b)调用fsync将确保日志都从重做日志缓冲写入磁盘。
为了保证 MySQL数据库上层二进制日志的写入顺序和InnoDB层的事务提交顺序一致[因为备份和恢复需要],MySQL数据库内部使用了prepare_commit_mutex这个锁。但是在启用这个锁之后,步骤3)中的步骤a)步不可以在其他事务执行步骤b)时进行,从而导致了groupcommit失效。
Percona公司都提出过解决方案。最后由MariaDB数据库的开发人员Kristian Nielse成了最终的“完美”解决方案。在这种情况下,不但MySQL数据库上层的场进制旦在写人是group commit的,InnoDB存储引擎层也是group commit的。此外还移除了原先的锁prepare_commit_mutex,从而大大提高了数据库的整体性。MySQL 5.6采用了类似的实现方式,并将其称为Binary Log Group Commit (BLGC)。

【事务控制语句】

在MySQL命令行的默认设置下,事务都是自动提交(auto commit)的,即执 行SQL语句后就会马上执行COMMIT操作。因此要显式地开启一个事务需使用命令 BEGIN、START TRANSACTION,或者执行命令SET AUTOCOMMIT=O,禁用当前会 话的自动提交
创建事务:
在事务内设置保存点:
单独设置隔离级别:

【分布式事务实现】

innodb实现了多节点之间的分布式事务。通过二阶段提交实现。XA事务由一个或多个资源管理器(Resource Managers)、一个事务管理器(Transaction Manager)以及一个应用程序(Application Program)组成。 在MySQL数据库的分布式事务中,资源管理器就是MySQL数据库,事务管理器 为连接MySQL服务器的客户端。图7-22显示了一个分布式事务的模型。
资源管理器:提供访问事务资源的方法。通常一个数据库就是一个资源管理器。
事务管理器:协调参与全局事务中的各个事务。需要和参与全局事务的所有资源 管理器进行通信。
应用程序:定义事务的边界,指定全局事务中的操作。
分布式事务使用两段式提交(two-phase commit)的方式。在第一阶段,所有参与全局事务的节点都开始准备(PREPARE),告诉事务管理器它们准备好提交了。在第阶段,事务管理器告诉资源管理器执行ROLLBACK还是COMMIT。如果任何一个节点显示不能提交,则所有的节点都被告知需要回滚。 可见与本地事务不同的是,分布式事 务需要多一次的PREPARE操作,待收到所有节点的同意信息后,再进行COMMIT或是 ROLLBACK操作
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值