如何在MySQL中提交事务?

MySQL 提交通常指的是在数据库中执行事务的提交操作,使用 COMMIT 命令来保存所有更改。

MySQL事务提交是一个复杂且重要的过程,它确保了数据在数据库中的一致性和完整性,以下是对MySQL事务提交流程的详细解释:

如何在MySQL中提交事务?

一、事务提交流程

MySQL事务提交通常采用两阶段提交协议,以确保存储引擎和二进制日志(binlog)的一致性,这两个阶段分别是prepare阶段和commit阶段。

1. prepare阶段

获取MDL_key::COMMIT锁:FTWRL会阻塞commit操作。

binlog prepare:将上一次commit队列中最大的seq_no写入本次事务的last_commit中,这一步对于用户发起的显式提交或DDL发起的隐式提交是可选的。

innodb prepare

获取线程的xid,设置为事务的xid。

修改Innodb中事务的状态为Prepare状态。

将undo日志端从active设置为prepare状态,并在undo段的第一个undo的last undo log header中写入xid。

2. commit阶段

XID_Event生成并写入binlog cache中:将事务中的写操作生成的event flush到binlog cache中,再写入xid event,这符合binlog中事务event顺序。

binlog flush

当前线程加入flush队列,如果flush队列为空,则当前线程为leader;否则为follower,非leader线程将被阻塞,直到commit之后被leader线程唤醒。

获取Lock log锁。

对flush队列进行fetch,处理的队列固定。

在innodb存储引擎中flush redo log,做innodb层redo持久化。

为flush队列中每个事务生成gtid。

将flush队列中每个线程的binlog cache flush到binlog文件中,包含三步:直接将GTID event写入binlog磁盘文件、将事务生成的别的event写入binlog file cache中、将binlog cache[IO cache] flush到文件。

判断binlog是否需要切换,设置切换标记,注意,这里是将事务的event写入binlog file cache后再判断,因此一个事务的binlog都位于同一个binlog文件中。

after_flush hook:如果sync_binlog != 1,更新binlog点位,通知dump线程向从节点发送event。

binlog sync

形成sync队列,第一个进入sync队列的leader为本阶段的leader,其他flush队列加入sync队列的leader线程将被阻塞,直到commit阶段被leader线程唤醒。

如何在MySQL中提交事务?

释放Lock log mutex,获取Lock sync mutex。

根据delay的设置来决定是否延迟一段时间,使得sync队列变大,last commit是在binlog prepare时生成,这时last commit尚未修改,因此加入sync队列的事务是同一组事务,可以提高从库mts效率。

fetch sync队列,对sync队列进行固化。

sync binlog file到磁盘中,需要根据sync_binlog的设置来决定是否刷盘。

如果sync_binlog = 1,更新binlog end pos,通知dump线程发送event。

commit阶段

如果需要按顺序提交:

sync队列加入commit队列,第一个进入的sync队列的leader为本阶段的leader,其他sync队列加入commit队列的leader会被阻塞,直到commit阶段后被leader线程唤醒,进入finish commit。

释放Lock sync mutex,获取lock commit mutex。

fetch commit队列,对commit队列进行固化。

调用after_sync hook:如果半同步复制为after_sync,则需要等待dump线程收到从节点对于commit队列中最大的binlog filename和pos的ack。

在Innodb层提交之前变更last_commit,将其变更为commit队列中最大的seqno。

COMMIT队列中每个事务按照顺序进行存储引擎层提交。

变更gtid_executed。

释放lock commit mutex。

如果不需要按顺序提交:

调用after_sync hook:如果半同步复制为after_sync,则需要等待dump线程收到从节点对于commit队列中最大的binlog filename和pos的ack。

收尾

leader线程唤醒组内成员,进行各自操作。

commit队列中事务清空binlog cache临时文件和内存。

如果不需要按顺序提交,则commit队列中线程各自进行存储引擎层的提交,提交完成之后更新gtid_executed。

如何在MySQL中提交事务?

决定是否进行binlog的rotate。

如果rotate了binlog,则根据expire_log_days判断是否需要清理binlog。

二、事务提交类型及应用场景

MySQL支持自动提交和手动提交两种模式:

自动提交:这是MySQL的默认模式,在这种模式下,每个SQL语句都被视为一个单独的事务,并在执行完毕后自动提交,这种模式简单易用,适合简单的数据操作场景,如日志记录、配置更新等。

手动提交:在这种模式下,事务中的多个SQL语句被视为一个整体,只有当事务被显式提交(COMMIT)时,更改才会写入数据库,如果事务中的任何语句失败,整个事务可以回滚(ROLLBACK),撤销所有更改,这种模式适用于需要复杂事务管理的场景,如银行转账、订单处理等。

三、常见问题及解决方法

问题1:为什么在手动提交模式下,事务没有提交?

原因可能是以下之一:

没有显式调用COMMIT语句。

事务中某个SQL语句失败,导致整个事务回滚。

数据库连接中断或其他网络问题。

解决方法包括:确保在事务结束时显式调用COMMIT语句;使用TRY…CATCH块捕获并处理事务中的错误;检查数据库连接和网络状态,确保连接稳定。

问题2:为什么在自动提交模式下,更改没有立即生效?

原因可能是以下之一:

数据库连接池中的连接处于事务状态。

数据库配置了延迟写入(delayed insert)。

数据库服务器负载过高,导致写入延迟。

解决方法包括:确保数据库连接池中的连接没有处于事务状态;检查并调整数据库配置,确保没有启用延迟写入;优化数据库服务器性能,减少负载。

小编有话说

MySQL事务提交是一个涉及多个步骤和机制的复杂过程,但它对于确保数据的一致性和完整性至关重要,了解并掌握这些细节可以帮助我们更好地使用MySQL数据库,避免潜在的数据丢失和不一致问题,根据具体的业务需求选择合适的事务提交模式也是非常重要的,希望本文能对你有所帮助!如果有更多问题,请随时提问。

原创文章,作者:未希,如若转载,请注明出处:https://www.kdun.com/ask/1455360.html

本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。

(0)
未希
上一篇 2025-01-03 21:00
下一篇 2025-01-03 21:07

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

产品购买 QQ咨询 微信咨询 SEO优化
分享本页
返回顶部
云产品限时秒杀。精选云产品高防服务器,20M大带宽限量抢购 >>点击进入