转自 http://www.cnblogs.com/exceptioneye/p/5451960.html

MySQL作为一种关系型数据库,已被广泛应用到互联网中的诸多项目中。今天我们来讨论下事务的提交过程。

MySQL体系结构

由于mysql插件式存储架构,导致开启binlog后,事务提交实质是二阶段提交,通过两阶段提交,来保证存储引擎和二进制日志的一致。

本文仅讨论binlog未打卡状态下的提交流程,后续会讨论打开binlog选项后的提交逻辑。

测试环境

OS:WIN7

ENGINE:

bin-log:off

DB:

测试条件

set autocommit=0;
-- ----------------------------

-- Table structure for `user`

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

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (

`id` int(20) NOT NULL,

`account` varchar(20) NOT NULL,

`name` varchar(20) NOT NULL,

PRIMARY KEY (`id`),

KEY `id` (`id`) USING BTREE,

KEY `name` (`name`) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

测试语句

insert into user values(1, 'sanzhang', '张三');
commit;

一般常用的DML:Data Manipulation Language 数据操纵语言,对表的数据进行操作,(insert、update、delete )语句 和 DCL:Data Control Language 数据库控制语言

(创建用户、删除用户、授权、取消授权)语句 和 DDL:Data Definition Language 数据库定义语言,对数据库内部的对象进行创建、删除、修改的操语句

,均是使用MySQL提供的公共接口mysql_execute_command,来执行相应的SQL语句。我们来分析下mysql_execute_command接口执行的流程:

mysql_execute_command

{

   switch (command)

   {

       case SQLCOM_INSERT:

                mysql_insert();

                break;

       case SQLCOM_UPDATE:

                mysql_update();

                break;

       case SQLCOM_DELETE:

                mysql_delete();

                break;

       ......

   }

   if thd->is_error()  //语句执行错误

     trans_rollback_stmt(thd);

  else

    trans_commit_stmt(thd);

}

从上述流程中,可以看到执行任何语句,最后都会执行trans_rollback_stmt或者trans_commit_stmt,这两个分别是语句回滚和语句提交。

语句提交,对于非自动模式下,主要有两个作用:

1、释放autoinc锁,这个锁主要用来处理多个事务互斥的获取自增序列。因此,无论最后执行的是语句提交还是语句回滚,该资源都是需要立马释放掉的。

2、标识语句在事务中的位置,方便语句级回滚。执行commit后,可以进入commit流程。

现在看下具体的事务提交流程:

mysql_execute_command

trans_commit_stmt

ha_commit_trans(thd, FALSE);

{

    TC_LOG_DUMMY:ha_commit_low

        ha_commit_low()   

            innobase_commit

            {

                //获取innodb层对应的事务结构

                trx = check_trx_exists(thd);

                if(单个语句,且非自动提交)

                {

                     //释放自增列占用的autoinc锁资源

                     lock_unlock_table_autoinc(trx);

                     //标识sql语句在事务中的位置,方便语句级回滚

                     trx_mark_sql_stat_end(trx);

                }

                else 事务提交

                {

                     innobase_commit_low()

                     {  

                        trx_commit_for_mysql();

                            <span style="color: #ff0000;">trx_commit</span>(trx); 

                     }

//确定事务对应的redo日志是否落盘【根据flush_log_at_trx_commit参数,确定redo日志落盘方式】

                    trx_commit_complete_for_mysql(trx);

trx_flush_log_if_needed_low(trx->commit_lsn);

log_write_up_to(lsn);

                }

            }

}
trx_commit

    trx_commit_low

        {

            trx_write_serialisation_history

            {

                trx_undo_update_cleanup //供purge线程处理,清理回滚页

            }

            trx_commit_in_memory

            {

                lock_trx_release_locks //释放锁资源

                trx_flush_log_if_needed(lsn) //刷日志

                trx_roll_savepoints_free //释放savepoints

            }

        }

MySQL是通过WAL方式,来保证数据库事务的一致性和持久性,即ACID特性中的C(consistent)和D(durability)。

WAL(Write-Ahead Logging)是一种实现事务日志的标准方法,具体而言就是:

1、修改记录前,一定要先写日志;

2、事务提交过程中,一定要保证日志先落盘,才能算事务提交完成。

通过WAL方式,在保证事务特性的情况下,可以提高数据库的性能。

从上述流程可以看出,提交过程中,主要做了4件事情,

1、清理undo段信息,对于innodb存储引擎的更新操作来说,undo段需要purge,这里的purge主要职能是,真正删除物理记录。在执行delete或update操作时,实际旧记录没有真正删除,只是在记录上打了一个标记,而是在事务提交后,purge线程真正删除,释放物理页空间。因此,提交过程中会将undo信息加入purge列表,供purge线程处理。

2、释放锁资源,mysql通过锁互斥机制保证不同事务不同时操作一条记录,事务执行后才会真正释放所有锁资源,并唤醒等待其锁资源的其他事务;

3、刷redo日志,前面我们说到,mysql实现事务一致性和持久性的机制。通过redo日志落盘操作,保证了即使修改的数据页没有即使更新到磁盘,只要日志是完成了,就能保证数据库的完整性和一致性;

4、清理保存点列表,每个语句实际都会有一个savepoint(保存点),保存点作用是为了可以回滚到事务的任何一个语句执行前的状态,由于事务都已经提交了,所以保存点列表可以被清理了。

关于mysql的锁机制,purge原理,redo日志,undo段等内容,其实都是数据库的核心内容。

MySQL 本身不提供事务支持,而是开放了存储引擎接口,由具体的存储引擎来实现,具体来说支持 MySQL 事务的存储引擎就是 InnoDB。

存储引擎实现事务的通用方式是基于 redo log 和 undo log。

简单来说,redo log 记录事务修改后的数据, undo log 记录事务前的原始数据。

所以当一个事务执行时实际发生过程简化描述如下:

  1. 先记录 undo/redo log,确保日志刷到磁盘上持久存储。
  2. 更新数据记录,缓存操作并异步刷盘。
  3. 提交事务,在 redo log 中写入 commit 记录。

在 MySQL 执行事务过程中如果因故障中断,可以通过 redo log 来重做事务或通过 undo log 来回滚,确保了数据的一致性。

这些都是由事务性存储引擎来完成的,但 binlog 不在事务存储引擎范围内,而是由 MySQL Server 来记录的。

那么就必须保证 binlog 数据和 redo log 之间的一致性,所以开启了 binlog 后实际的事务执行就多了一步,如下:

  1. 先记录 undo/redo log,确保日志刷到磁盘上持久存储。
  2. 更新数据记录,缓存操作并异步刷盘。
  3. 将事务日志持久化到 binlog。
  4. 提交事务,在 redo log 中写入commit记录。

这样的话,只要 binlog 没写成功,整个事务是需要回滚的,而 binlog 写成功后即使 MySQL Crash 了都可以恢复事务并完成提交。

要做到这点,就需要把 binlog 和事务关联起来,而只有保证了 binlog 和事务数据的一致性,才能保证主从数据的一致性。

所以 binlog 的写入过程不得不嵌入到纯粹的事务存储引擎执行过程中,并以内部分布式事务(xa 事务)的方式完成两阶段提交。

参考

1、《高性能MySQL》

1024MySQL事物提交机制的更多相关文章

  1. innodb二阶段日志提交机制和组提交解析

    前些天在查看关于innodb_flush_log_at_trx_commit的官网解释时产生了一些疑问,关于innodb_flush_log_at_trx_commit参数的详细解释参见官网: htt ...

  2. MysqL自动提交机制的关闭

    MysqL在执行一句数据库操作命令的时候,通常都是自动提交的.常用引擎下有两种,分别是MyIsam和InnoDB,MyIsam是不支持事务处理的,但InnoDB支持,但InnoDB在不开启事务处理的情 ...

  3. Spring对Hibernate的session生效期(事物提交管理)介绍

    在Hibernate中我们每次进行一个操作的的时候我们都是要先开启事务,然后进行数据操作,然后提交事务,关闭事务,这样做的原因是因为Hibernate默认的事务自动提交是false,它是需要人为的手动 ...

  4. spring事物传播机制 事物隔离级别

    Spring事务类型详解: PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PROPAGATION_SUPPORTS--支持当前事务,如 ...

  5. Redis集群事物提交异常Multi-key operations must involve a single slot

    redis做完集群后不同键在同一事物中提交,因为key的hash计算结果不同不能分配到同一个分片上,因此出现此异常. 解决方案:在本次事物的key内添加"{tag}",这时redi ...

  6. Spring事物管理机制简单学习

    首先spring并不直接管理事物,而是提供了多种事物管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现. Spring管理事物的接口是org.s ...

  7. spring事物传播机制与隔离级别

    转载自:http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html7个传播行为,4个隔离级别, Spring事务的传播行为和隔 ...

  8. PDO的事物处理机制

    Mysql的事务处理: 1.MySQL目前只有InnoDB 和BDB两个数据表类型才支持事务. 2.在默认条件下,MySQL是以自动提交(autocommit)模式运行的,这就意味着所执行的每一个语句 ...

  9. ADF一个EO的事物提交周期

    客户端通过传递键对象调用实体定义的findByPrimaryKey(),获得EO.ADF框架首先检查实体缓存, 如果在实体缓存中没有找到实体,就执行SQL SELECT查询,从数据库读取行.示例如下: ...

随机推荐

  1. java File类常用方法

    file类常用方法 delete()删除此抽象路径名表示的文件和目录. equals()测试此抽象路径名与给定对象是否相等. exists()测试此抽象路径名表示的文件或目录是否存在. getName ...

  2. APP专业的开发公司都有这样一套开发流程,强烈建议收藏!

    下面让我们来剖析到底是如何开发App的呢? 1.App界面设计开发: 通过客户提出需求,需要头脑风暴得出合适的方案和设计理念; 确认页面风格,确定整个界面的布局.关键截面的设计.文字.及其他的设计 G ...

  3. 关于使用Mybatis的使用说明(一)【未完善待更新】

    (一)搭建Mybatis环境 (1)先导入常用的jar包:并且需要将lib文件夹下的包导入到项目中 (2)创建config文件夹,配置log4j.properties文件 # Global loggi ...

  4. ORA-03206,当表空间不够时,如何以添加数据文件的方式扩展表空间

    准备导入一个数据库,大约为33G,开始创建的空库表空间为自增到20G,结果自然不够,然后就开始自动扩展表空间大小 使用的如下语句 --自动扩展表空间大小 ALTER DATABASE DATAFILE ...

  5. 学号:201621123032 《Java程序设计》第3周学习总结

    1:本周学习总结 1. 写出你认为本周学习中比较重要的知识点关键词. 类,对象,封装,继承,方法. 2. 用思维导图或者Onenote或其他工具将这些关键词组织起来 2:书面作业 2.1:以面向对象方 ...

  6. 【Swift】 iOS开发容易产生Bug的地方

    1.隐藏navigationBar(尤其是多级隐藏) 2.共用collectionView或tableView 3.继承关系下,注意覆写父类时的super方法的调用 4.关于权限的问题(相机权限,相册 ...

  7. vue项目结构

    前言 我在 搭建vue项目环境 简单说明了项目初始化完成后的目录结构. 但在实际项目中,src目录下的结构需要跟随项目做一些小小的调整. 目录结构 ├── src 项目源码目录 │ ├── api 所 ...

  8. 使用caffe训练mnist数据集 - caffe教程实战(一)

    个人认为学习一个陌生的框架,最好从例子开始,所以我们也从一个例子开始. 学习本教程之前,你需要首先对卷积神经网络算法原理有些了解,而且安装好了caffe 卷积神经网络原理参考:http://cs231 ...

  9. Microsoft dynamic 批量更新

    //批量处理 ExecuteMultipleRequest multipleRequest = new ExecuteMultipleRequest() { Settings = new Execut ...

  10. Golang学习--开篇

    最近开始接收一个新项目,是使用Golang写的,需要重新捡起Golang来,于是就有了这个系列博客. Golang的环境配置,我就不说了,让我们直接开始. Golang官网:https://golan ...