InnoDB---深入理解事务提交--01

http://blog.163.com/li_hx/blog/static/1839914132016112991511518/

当事务正常执行结束时,事务的提交操作,是实现事务原子性的主要操作之一,这个过程很重要。如下我们重点分析事务提交过程中一些重要环节。

 

一 事务提交的整体过程

    InnoDBMySQL Server联合实现了事务的提交全程,相关过程参见表10-2,在这个表里面,从上到下,是一个事务提交过程的栈,上面是栈顶下面是栈底,底层的函数调用了上层的函数。

 

10-2 事务提交的相关函数栈表

函数名称与作用

函数过程

trx_commit_in_memory

在内存中标识事务完成,然后释放事务锁

1.   调用lock_trx_release_locks()释放锁

2.   断言事务的状态是在内存中已经完成(标志是上一步完成设置的)

3.   调用trx_undo_insert_cleanup()释放插入的UNDO日志

4.   生成新的LSN

5.   根据innodb_flush_log_at_trx_commit参数值的情况确定是否调用trx_flush_log_if_needed()刷出日志到物理存储(即是否实现预写日志机制)

6.   如果是回滚操作,则为回滚操作设置一些值,如设置事务的状态为宏TRX_STATE_FORCED_ROLLBACK

7.   重新初始化事务对象的结构体值以备再用

trx_commit_low

 

1.   Mini-Transaction事务提交

2.   调用trx_commit_in_memory()完成事务在内存中的提交等操作

trx_commit

1.   调用trx_commit_low()完成事务提交

2.   也会被trx_rollback_finish()调用,用于回滚操作

trx_commit_for_mysql

1.   根据事务的状态,执行不同的操作。调用trx_commit是因为事务的状体需要从TRX_STATE_ACTIVETRX_STATE_PREPARED转变为TRX_STATE_COMMITTED_IN_MEMORY

innobase_commit_low

1.   调用trx_commit_for_mysql()完成事务提交

innobase_commit

1.   调用innobase_commit_low()完成事务提交(设置事务提交标志并释放事务相关的锁)

2.   调用trx_commit_complete_for_mysql()刷出日志

 

以上是InnoDB层的事务提交相关代码,从上到下是从栈顶到栈底的主要函数

ha_commit_low

MySQL Server层通过handle接口对底层的存储进行事务管理的操作,通过函数指针ht->commit()调用了InnoDBinnobase_commit()函数

TC_LOG_DUMMY::commit

MySQL层不提供REDO日志服务,但提供了一个伪接口来模拟逻辑上的日志提交操作

ha_commit_trans

MySQL层进行的事务提交

trans_commit_stmt 

trans_commit

MySQL层进行的事务提交,前者是对单语句事务进行提交,后者是对多语句事务进行提交







 

二 事务提交和日志刷出之间的关系

    通常情况下,数据库引擎通过严格两阶段锁(SS2PL,参见第二章)来实现并发控制技术,但为了满足数据的一致性要求,事务的ACID特性中的一致性C要求事务在提交前,要先刷出日志即符合WAL预先日志机制。但是,InnoDB支持事务的提交但却没有遵循WAL预先日志机制,这就可能带来数据不一致的问题。

    如下是对innobase_commit()函数的主要流程分析,从这个分析可以看出,事务先被设置的提交标识,然后锁被释放。之后再执行trx_commit_complete_for_mysql()函数完成日志的刷出操作。所以我们说InnoDB不符合WAL预先日志机制。

/*****************************************************************//**

Commits a transaction in an InnoDB database or marks an SQL statement ended.

@return 0 or deadlock error if the transaction was aborted by another higher priority transaction. */

static

int

innobase_commit  //提交一个事务,完成事务提交的标识,然后刷出日志(如此的方式,违反了WAL预写日志的机制

    handlerton*    hton,          /*!< in: InnoDB handlerton */ //InnoDB引擎的句柄

    THD*           thd,           /*!< in: MySQL thread handle of the user for whom the transaction should be committed */ //用户会话

    bool           commit_trx)    /*!< in: true – commit transaction false – the current SQL statement ended */  //是否提交

{…

    if (commit_trx  //值为TRUE表示要提交事务

        || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {

        innobase_commit_low(trx); //调用栈: -> trx_commit_for_mysql() -> trx_commit(trx) -> trx_commit_low() -> trx_commit_in_memory() -> lock_trx_release_locks()lock_trx_release_locks()这个函数中执行如下重要代码

                //trx->state = TRX_STATE_COMMITTED_IN_MEMORY;  即在内存中设置事务提交已经完成的标志,本事务的数据即刻被其他事务可见

                //…  省略一些代码

                //lock_release(trx);  在设置事务提交已经完成的标志后才释放锁。锁在设置提交标志后才释放,符合SS2PL协议

        /* Now do a write + flush of logs. */

        if (!read_only) {

            trx_commit_complete_for_mysql(trx);  //重要的步骤:刷出日志(刷出日志的过程可参见下一节“日志落盘”中的标题二)

        }

    } else {    //不提交事务

    }

}

    原文作者:mysql
    原文地址: https://blog.csdn.net/yanzongshuai/article/details/53958198
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞