MySQL Innodb的事务部分 函数调用关系

本文详细解析了MySQL中InnoDB存储引擎的事务处理流程,包括XA事务、普通事务及单条语句的处理过程,涉及函数调用顺序、锁机制、binlog与redo log的交互等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

花了两天的时间,大概了解了下Innodb部分跟事务相关的函数代码,其实也就那么几个函数,但每个函数会把几种情况放在一起处理

下面是我整理的关于XA事务、普通事务以及单独语句的函数调用,做个记录,主要用来在gdb代码的时候,做断点用。。。

xa start 'pp'

trans_xa_start
trans_begin (隐含的commit任何当前的事务并释放锁)
trans_check :(/* Conditions under which the transaction state must not change. */)
(likely(value)、unlikely(value))
ha_commit_trans()
thd->mdl_context.release_transactional_locks()
trans_commit_stmt



mysql> insert into x4 values(5);


trans_commit_stmt
ha_commit_trans
binlog_prepare:空函数
innobase_xa_prepare
对于xa事务,仅仅标记为ended
……
ha_commit_one_phase
binlog_commit(该函数在每执行一次statement后)
cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF)
//binlog_commit_flush_trx_cache:将binlog cache中的内容写到文件中。
//binlog_flush_cache
innobase_commit (对这条语句而言,仅仅标记该语句结束了,而不做commit)



mysql> xa end 'pp';
trans_commit_stmt
after_commit


mysql> xa prepare 'pp';
trans_xa_prepare
ha_prepare
binlog_prepare
innobase_xa_prepare


……
trx_prepare_for_mysql
trx_prepare_off_kernel-------根据my.cnf的选项决定是否刷新log到磁盘----做一次group commit

当不为XA_PREPARE语句时。。。
if (thd_sql_command(thd) != SQLCOM_XA_PREPARE
pthread_mutex_lock(&prepare_commit_mutex);
trans_commit_stmt
after_commit



mysql> xa commit 'pp';
trans_xa_commit
92 /*
693 * Acquire metadata lock which will ensure that COMMIT is blocked
694 * by active FLUSH TABLES WITH READ LOCK (and vice versa COMMIT in
695 * progress blocks FTWRL).We allow FLUSHer to COMMIT; we assume FLUSHer knows what it does.
*/
加锁……
ha_commit_one_phase(thd, 1)
binlog_commit
binlog_commit_flush_trx_cache
binlog_flush_cache
innobase_commit
innobase_commit_low
trx_commit_for_mysql
trx_commit_off_kernel(看起来似乎是真的要提交了。。。。)


if (trx->declared_to_be_inside_innodb) { //不知道为什么没有持有prepare_commit_mutex


trx_commit_complete_for_mysql







log_write_up_to:(log0log.c)
实现group commit,这里仅考虑flushto_disk为真的情况,即需要向磁盘中fsync log
loop:
当ut_dulint_cmp(log_sys->flushed_to_disk_lsn, lsn) >= 0
即lsn小于或等于全局变量log_sys中的记录的上次刷新的lsn时,直接返回

log_sys->n_pending_writes > 0
if (flush_to_disk
&& ut_dulint_cmp(log_sys->current_flush_lsn, lsn)
>= 0) {
/* The write + flush will write enough: wait for it to
complete */


goto do_waits;
}





///////////////
log-bin = 1
sync_binlog = 1


------------------------------------------


mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

trans_begin()
trans_commit_stmt


mysql> insert into x4 values (10);
Query OK, 1 row affected (1 min 1.69 sec)

trans_commit_stmt
ha_commit_trans
binlog_prepare
innobase_xa_prepare
ha_commit_one_phase
binlog_commit(看起来什么也没做,仅仅做了cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);)
cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
innobase_commit(同样仅仅是做一些标记)


mysql> commit ;


trans_commit
ha_commit_trans
binlog_prepare
innodb_xa_prepare
trx_prepare_for_mysql
mysql_mutex_lock(&prepare_commit_mutex);


MYSQL_BIN_LOG::log_xid


ha_commit_one_phase
binlog_commit(似乎木有做写binlog,莫非已经被group commit了。。。= =! log_xid..)
innobase_commit
innobase_commit_low
mysql_mutex_unlock(&prepare_commit_mutex);
trx_commit_complete_for_mysql(trx);
trans_commit_stmt




---------------------------------------------
单独执行一条语句:
mysql> insert into x4 values (11);

trans_commit_stmt()
ha_commit_trans()
binlog_prepare
innobase_xa_prepare
trx_prepare_for_mysql
mysql_mutex_lock(&prepare_commit_mutex);

if (error || (is_real_trans && xid &&
(error= !(cookie= tc_log->log_xid(thd, xid)))))


ha_commit_one_phase
binlog_commit
innobase_commit
innobase_commit_low(trx);
mysql_mutex_unlock(&prepare_commit_mutex);
trx_commit_complete_for_mysql(trx);

MySQL没有内置的雪花算法函数,需要自己编写实现。可以按照以下步骤编写一个简单的雪花算法函数: 1. 创建一个存储过程,用于生成雪花ID。 DELIMITER $$ CREATE PROCEDURE `generate_snowflake_id`( OUT `id` VARCHAR(20) ) BEGIN DECLARE `worker_id` INT UNSIGNED DEFAULT 1; DECLARE `data_center_id` INT UNSIGNED DEFAULT 1; DECLARE `timestamp` BIGINT UNSIGNED DEFAULT 0; DECLARE `sequence_id` BIGINT UNSIGNED DEFAULT 0; SELECT FLOOR(UNIX_TIMESTAMP()*1000) INTO `timestamp`; SELECT `sequence_id` INTO `sequence_id` FROM `snowflake_sequence` WHERE `id` = 1 FOR UPDATE; UPDATE `snowflake_sequence` SET `sequence_id` = `sequence_id` + 1 WHERE `id` = 1; SET `id` = LPAD(BIN(`timestamp`), 41, '0'); SET `id` = CONCAT(`id`, LPAD(BIN(`data_center_id`), 5, '0')); SET `id` = CONCAT(`id`, LPAD(BIN(`worker_id`), 5, '0')); SET `id` = CONCAT(`id`, LPAD(BIN(`sequence_id`), 12, '0')); END$$ DELIMITER ; 2. 创建一个雪花序列表,用于存储序列号。表中只需要一个字段,用于存储序列号。 CREATE TABLE `snowflake_sequence` ( `id` int(11) NOT NULL AUTO_INCREMENT, `sequence_id` bigint(20) NOT NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 3. 向雪花序列表中插入一条记录,初始序列号为0。 INSERT INTO `snowflake_sequence` (`sequence_id`) VALUES (0); 4. 调用存储过程,生成雪花ID。 CALL `generate_snowflake_id`(@id); SELECT @id; 需要注意的是,雪花算法需要满足以下格式要求:第1位为符号位(0表示正数,1表示负数),接下来41位为时间戳(毫秒级),然后是5位数据中心ID、5位机器ID和12位序列号。因此,需要根据实际情况调整存储过程中的参数。此外,使用雪花算法生成ID可能会导致一些性能问题,需要谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值