COMMIT
命令来保存所有更改。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线程唤醒。
释放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。
决定是否进行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
本网站发布或转载的文章及图片均来自网络,其原创性以及文中表达的观点和判断不代表本网站。如有问题,请联系客服处理。
发表回复