• MySQL事务篇


    一、一条Insert语句
    为了故事的顺利发展,我们需要创建一个表
     
    CREATE TABLE t (
    id INT PRIMARY KEY,
    c VARCHAR(100)
    ) Engine=InnoDB CHARSET=utf8;
     
    然后向这个表里插入一条数据:
    现在表里的数据就是这样的:
    二、执行流程
    CREATE TABLE t (
    id INT PRIMARY KEY,
    c VARCHAR(100)
    ) Engine=InnoDB CHARSET=utf8;
    1
    2
    3
    4
    1 INSERT INTO t VALUES(1, '刘备');
    mysql> SELECT * FROM t;
    +----+--------+
    | id | c |
    +----+--------+
    | 1 | 刘备 |
    +----+--------+
    1 row in set (0.01 sec)
     
     

    二、事务介绍 

    1事务概述

    MySQL是一个服务器/客户端架构的软件,对于同一个服务器来说,可以有若干个客户端与之连接,每 个客户端与服务器连接上之后,就可以称之为一个会话(Session )。我们可以同时在不同的会话里输 入各种语句,这些语句可以作为事务的一部分进行处理。不同的会话可以同时发送请求,也就是说服务 器可能同时在处理多个事务,这样子就会导致不同的事务可能同时访问至IJ相同的记录。我们前边说过事 务有一个特性称之为隔离性,理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该 事务提交之后,其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大,所以设计数据库 的大叔提出了各种隔离级别,来最大限度的提升系统并发处理事务的能力,但是这也是以牺牲一定的 离性来达到的。

    事务是数据库最为重要的机制之一,凡是使用过数据库的人,都了解数据库的事务机制,也对ACID四个 基本特性如数家珍。但是聊起事务或者acid的底层实现原理,往往言之不详,不明所以。在MySQL中的 事务是由存储引擎实现的,而且支持事务的存储引擎不多,我们主要讲解InnoDB存储弓|擎中的事务。 所以,今天我们就一起来分析和探讨InnoDB的事务机制,希望能建立起对事务底层实现原理的具体了 解。

     
     

    数据库事务具有ACID四大特性。ACID是以下4个词的缩写:

    原子性atomicity):事务最小工作单元,要么全成功,要么全失败

    一致性consistency):事务开始和结束后,数据库的完整性不会被破坏。

    隔离性isolation):不同事务之间互不影响,四种隔离级别为RU (读未提交)、RC (读已提 交)、RR (可重复读)、SERIALIZABLE (串行化)。

    持久性durability):事务提交后,对数据的修改是永久性的,即使系统故障也不会丢失。

    2隔离级别

    1)未提交读(READ UNCOMMITTED/RU

    脏读:一个事务读取到另一个事务未提交的数据。

    如果一个事务读到了另一个未提交事务修改过的数据,那么这种隔离级别就称之为未提交读(英文名:

    READ UNCOMMITTED )

    2)已提交读READ COMMITTED/RC

    不可重复读:一个事务因读取到II另一个事务已提交的update。导致对同一条记录读取两次以上的 结果不一致。

    如果一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并 提交后,该事务都能查询得到最新值,那么这种隔离级别就称之为已提交读(英文名:READ COMMITTED )

    3)可重复读(REPEATABLE READ/RR
    幻读:一个事务因读取至II另一个事务闩提交的insert数据或者delete数据导致对同一张表读取两 次以上的结果不一致。

    在一些业务场景中,一个事务只能读到另一个已经提交的事务修改过的数据,但是第一次读过某条记录 后,即使其他事务修改了该记录的值并且提交,该事务之后再读该条记录时,读到的仍是第一次读到的 值,而不是每次都读到不同的数据。那么这种隔离级别就称之为可重复读(英文名:REPEATABLE READ)

    4)串行化SERIALIZABLE)

    以上3种隔离级^都允许对同一a记录进行读-读、-写、-读的并发操作,如果我们不允许医写、 -读的并发操作,

    三、事务和MVCC底层原理详解

    1、思考:丢失更新

    两个事务针对同一数据都发生修改J菊作时,会存在丢失更新问题。

    这种方案比较简单粗暴,就是一个事务去读取a瓣的时候,就上锁,不允许其他事务来操作。 MySQL加锁之后就是当前读。假如当前事务只是加共享锁,那么其他事务就不能有排他锁,也就是不能 修改数据;同段如当前事务需要加排他锁,那么其他事务就不能持有田可锁。总而言之,能加锁成功, 就确保了除了当前事务之外,其他事务不会对当前数据产生影响,所以自然而然的,当前事务读取到的 瓣就只能是最新的,而不会是快照数据 

    当然使用MVCC (MVCC多版本的并发控制,英文全称:Multi Version Concurrency Control)机制可 以解决这个问题。查询总额事务先读取了用户A的账户存款,然后转账事务会修改用户A和用户B账户存 款,查询总额事务读取用户B存款时不会读取转账事务修改后的数据,而是读取本事务开始时的数据副 本(在REPEATABLE READ隔离等级下)。

     

    MVCC使得数据库读不会对数据加锁,普通的SELECT请求不会加锁,提高了数据库的并发处理能力。借 助MVCC,数据库可以实现READ COMMIXED, REPEATABLE READ等隔离级用户可以查看当前数 据的前一个或者前几个历史版本,保证了ACID中的I特性(隔离性)。

    InnoDBMVCC实现

    我们首先来看一下wi ki上对MVCC的定义:

    Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory.

    由定义可知,MVCC是用于数据库提供并发访问控制的并发控制技术。与MVCC相对的是基于锁的并发控 制,Lock-Based Concurrency Control。MVCC最大的好处,相信也是耳熟能详:读不加锁,读写不 冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,这也是为 什么现阶段,几乎所有的RDBMS,都支持了MVCC。

    多版本并发控制仅仅是一种技术概念,并没有统一的实现标准,其核心理念就是数据快照,不同的事务 访问不同版本的数据快照,从而实现不同的事务隔离级别。虽然字面上是说具有多个版本的数据快照, 但这并不意味着数据库必须拷贝数据,保存多份数据文件,这样会浪费大量的存储空间。InnoDB通过事 务的undo日志巧妙地实现了多版本的数据快照。

    SELECT

    InnoDB会根据以下两个条件检查每行记录:

    1. InnoDB只查找版本早于当前事务版本的数据行(也就是,行的事务编号小于或等于当前事务的事 务编号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或 者修改过的。

    2. 删除的行要事务ID判断,读取到事务开始之前状态的版本。

    只有符合上述两个条件的记录,才能返回作为查询结果。

    INSERT

    InnoDB为新插入的每一行保存当前事务编号作为行版本号。

    DELETE

    InnoDB为删除的每一行保存当前事务编号作为行删除标识。

    UPDATE

    InnoDB为插入一行新记录,保存当前事务编号作为行版本号,同时保存当前事务编号到原来的行作为行 删除标识。

    保存这两个额外事务编号,使大多数读操作都可以不用加锁。这样设计使得读瓣操作很简单,性能很 好,并且也能保证只我取到符合标准的行。不足之处是每行记謡隔要额外的存储空间,需要噸多 的行检查工作,以及一些额外的维护工作。

    MVCC只在REPEATABLE READ和READ COMMITIED两个隔离级§!]下工作。其他两个隔离级§!]都和 MVCC不兼容,因为READ UNCOMMITIED总是读取最新的数据行,而不是符合当前事务版本的数 据行。而SERIALIZABLE则会对所有读取的行都加锁

    2) undo log

    根据行为的不同,undo log分为两种:1 nsert undo log和update undo log

    • insert undo log:

    1 是在i nsert操作中产生的undo log:

    2 因为insert操作的记录只对事务本身可见,对于其它事务此记录是不可见的,所以insert undo log可以在事务提交后直接删除而不需要进行purge操作。

    为了更好的支持并发,InnoDB的多版本一致性读是采用了基于回滚段的的方式。另外,对于更新 和删除操作,InnoDB并不是真正的删除原来的记录,而是设置记录的delete mark为1。因此为了 解决数据Page和Undo Log膨胀的问题,需要引入purge机制进行回收。Undo log保存了记录修改 前的镜像。在InnoDB存储弓|擎中,undo log分为:

    • insert undo log

    • update undo log

    insert undo log是指在insert操作中产生的undo log。由于insert操作的记录,只是对本事务可 见,其他事务不可见,所以undo log可以在事务提交后直接删除,而不需要purge操作。

    叩date undo log是指在delete和up date操作中产生的undo log。该undo log会被后续用于MVCC 当中,因此不能提交的时候删除。提交后会放入undo log的链表,等待purge线程进行最后的删 除。

     

    3) Readview

    对于使用READ UNCOMMITTED隔离级的事务来说,直接读取记录的最新版本就好了。对于使用 SERIALIZABLE隔离级§!]的事务来说,使用加锁的方式来访问记录。对于使用READ COMMITTED REPEATABLE READ隔离级§啲事务来说,就需要用到我们上边所说的版本链了。核心问题就是需要判 断一下版本链中的哪个版本是当前事务可见的。所以设计innoDB的设计者提出了一个ReadView的概 念,这个Readview中主要包含当前系统中还有哪些活跃的读写事务,把它们的事务id放到一个列表 中,我们把这个列表命名为为m_ids

    这样在访问某条记录时,只需要按照下边的步骤判断记录的某个版本(版本链中的版本)是否可见:

    •如被访问版本的trx_i d属性值小干m_i ds列表中最小的事务d,表明生成该版本的事务在生成 Readview前已经提交,所该版本可以诚当前事务访问。

    •如被访问版本的trx_i d属性值大干m_i ds列表中最大的事务d,表明生成该版本的事务在生成 Readview后才生成,所以该版本不可以被当前事务访问

    •如果诚访问版本的trx i d属性值在m i ds列表中晶大的事务d和晶小事务id力间,那就霊要判断 —下trx_id属性值是不是在m_ids列表中如果在,说明创建Readvi ew时生成该版本的事务还 是活跃的,该版本不可以被访问;如果不在,说明创建Readview时生成该版本的事务已经被提 交,该版本可以被访问

    如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上 边的步骤判断可见性,依此类推,直到版本链中的最后一个版本,如果最后一个版本也不可见的 话,那么就意味着该条记录对该事务不可见,查询结果就不包含该记录。

    在MySQL中,READ COMMITTED和REPEATABLE READ隔离级别的的一个非常大的区别就是它们生成 Readvi ew的时机不同,我们来看一下。

     

    6MVCC总结

    从上边的描述中我们可以看出来,所谓的MVCC(Multi-Version Concurrency Control,多版本并发控 制)指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的 SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而 提升系统性能。

    READ COMMITTD、REPEATABLE READ这两个隔离级别的一个很大不同就是生成Readview的时机不 同,READ COMMITTD在每一次进行普通SELECT操作前都会生成一个Readview,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个ReadVi ew,之后的查询操作都重复这个ReadVi ew 就好了。

     
     

    四、事务回滚和数据恢复

    事务的隔离性由多版本控制机制和锁实现,而原子性,持久性和一致性主要是通过redlog undo log Force Log at Commit机制机制来完成的。redo log用于在崩溃时恢复数据,undo log用于对事务的影 响进行撤销,也可以用于多版本控制。而Force Log at Commit机制保证事务提交后redo log日志都已经 持久化。

    开启一个事务后,用户可以使用COMMIT来提交,也可以用ROLLBACK来回滚。其中COMMIT或者 ROLLBACK执行成功之后,数据一定是会被全部保存或者全部回滚到最初状态的,这也体现了事务的原 子性。但是也会有很多的异常情况,比如说事务执行中途连接断开,或者是执行COMMIT或者 ROLLBACK时发生错误,Server Crash等,此时数据库会自动进行回滚或者重启之后进行恢复。

    我们先来看一下redo log的原理,redo log顾名思义,就是重做日志,每次数据库的SQL操作导致的数据 变化它都会记录一下,具体来说,redo log是物理日志,记录的是数据库页的物理修改操作。如果数据 发生了丢失,数据库可以根据red。log进行数据恢复。

    InnoDB通过Force Log at Commit机制实现事务的持久性,即当事务COMMIT时,必须先将该事务的所 有日志都写入到redo log文件进行持久化之后,COMMIT操作才算完成。

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    基于Windows环境下Myeclipse10.0下载安装破解及jdk的下载安装及环境变量的配置
    51 Nod 1791 合法括号子段【分治+字符串】
    一步一步深入理解Dijkstra算法
    POJ 3662 Telephone Lines【Dijkstra最短路+二分求解】
    拍拍网接入微信卡包备战双12圣诞购物季
    公众平台认证订阅号接口调整 增加群发接口等,可授权登录
    搜狗搜索推广品牌专区新增微信互动区展示企业微信公众号内容
    WP8版微信5.4发布 新增夜间模式 暂没小视频
    Kik CEO Ted Livingston发博称要成为西方的微信?
    微信"附近的人"新增商家公众号入驻功能
  • 原文地址:https://www.cnblogs.com/zhouyideboke/p/16408488.html
Copyright © 2020-2023  润新知