zoukankan      html  css  js  c++  java
  • 温故知新-Mysql锁&事务&MVCC



    锁概述

    锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢)。
    在数据库中,除传统的计算资源(如 CPU、RAM、I/O 等)的争用以外,数据也是一种供许多用户共享的资源。如
    何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的
    一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂

    锁分类

    • 从对数据操作的粒度分

    1) 表锁:操作时,会锁定整个表。
    2) 行锁:操作时,会锁定当前操作行。

    • 从对数据操作的类型分

    1) 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响
    2) 写锁(排它锁):当前操作没有完成之前,它会阻断其他写锁和读锁

    • Mysql 锁

    相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。下表中罗
    列出了各存储引擎对锁的支持情况:
    锁

    • MySQL这3种锁的特性可大致归纳如下 :

      • 表锁

      偏向MyISAM 存储引擎,开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

      • 行锁

      偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

      • 页面锁

      开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

    MyISAM 表锁

    • 对MyISAM 表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;
    • 对MyISAM 表的写操作,则会阻塞其他用户对同一表的读和写操作;

    简而言之,就是读锁会阻塞写,但是不会阻塞读。而写锁,则既会阻塞读,又会阻塞写。

    • 此外,MyISAM 的读写锁调度是写优先,这也是MyISAM不适合做写为主的表的存储引擎的原因。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

    InnoDB 行锁

    • 行锁特点 :偏向InnoDB 存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
    • InnoDB 与 MyISAM 的最大不同有两点:一是支持事务;二是 采用了行级锁。

    事务及其ACID属性

    • 事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个特性,简称为事务ACID属性。
      事务ACID属性
    • 并发事务处理带来的问题
      在这里插入图片描述
    • 事务隔离级别
      • 为了解决上述提到的事务并发问题,数据库提供一定的事务隔离机制来解决这个问题。数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使用事务在一定程度上“串行化” 进行,这显然
        与“并发” 是矛盾的。
      • 数据库的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、
        Serializable,这四个级别可以逐个解决脏写、脏读、不可重复读、幻读这几类问题。
        在这里插入图片描述
        Mysql 的数据库的默认隔离级别为 Repeatable read;

    InnoDB 的行锁模式

    InnoDB 实现了以下两种类型的行锁。

    • 共享锁(S):又称为读锁,简称S锁,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
    • 排他锁(X):又称为写锁,简称X锁,排他锁就是不能与其他锁并存,如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁,但是获取排他锁的事务是可以对数据就行读取和修改。

    对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会加任何锁;

    • 无索引行锁升级为表锁

    如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。

    • 间隙锁危害

    当我们用范围条件,而不是使用相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据进行加锁; 对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)” ,InnoDB也会对这个 “间隙” 加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)

    注意

    • InnoDB存储引擎由于实现了行级锁定,虽然在锁定机制的实现方面带来了性能损耗可能比表锁会更高一些,但是在整体并发处理能力方面要远远由于MyISAM的表锁的。当系统并发量较高的时候,InnoDB的整体性能和MyISAM相比就会有比较明显的优势。

    • 但是,InnoDB的行级锁同样也有其脆弱的一面,当我们使用不当的时候,可能会让InnoDB的整体性能表现不仅不
      能比MyISAM高,甚至可能会更差。

    1. 尽可能让所有数据检索都能通过索引来完成,避免无索引行锁升级为表锁。
    2. 合理设计索引,尽量缩小锁的范围
    3. 尽可能减少索引条件,及索引范围,避免间隙锁
    4. 尽量控制事务大小,减少锁定资源量和时间长度
    5. 尽可使用低级别事务隔离(但是需要业务层面满足需求)

    MVCC

    MVCC (Multiversion Concurrency Control) 中文全程叫多版本并发控制,是现代数据库(包括 MySQL、Oracle、PostgreSQL 等)引擎实现中常用的处理读写冲突的手段,目的在于提高数据库高并发场景下的吞吐性能。

    • 如此一来不同的事务在并发过程中,SELECT 操作可以不加锁而是通过 MVCC 机制读取指定的版本历史记录,并通过一些手段保证保证读取的记录值符合事务所处的隔离级别,从而解决并发场景下的读写冲突。

    InnoDB 中的 MVCC

    • InnoDB MVCC 实现原理的关键

    1、事务版本号
    2、表的隐藏列。
    3、undo log
    4、 read view

    InnoDB 中 MVCC 的实现方式为:每一行记录都有两个隐藏列:DATA_TRX_ID、DATA_ROLL_PTR(如果没有主键,则还会多一个隐藏的主键列)。
    在这里插入图片描述

    • DATA_TRX_ID

    记录最近更新这条行记录的事务 ID,大小为 6 个字节

    • DATA_ROLL_PTR

    表示指向该行回滚段(rollback segment)的指针,大小为 7 个字节,InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织。

    • DB_ROW_ID

    行标识(隐藏单调自增 ID),大小为 6 字节,如果表没有主键,InnoDB 会自动生成一个隐藏主键,因此会出现这个列。另外,每条记录的头信息(record header)里都有一个专门的 bit(deleted_flag)来表示当前记录是否已经被删除。

    • 组织 Undo Log 链
      在这里插入图片描述
    • 如何实现一致性读 —— ReadView
      InnoDB 为了解决这个问题,设计了 ReadView(可读视图)的概念。
      ReadView :每个 SELECT 语句开始时,会生成一致性视图,ReadView 中是当前活跃的事务 ID 列表,称之为 m_ids,其中最小值为 up_limit_id,最大值为low_limit_id,事务 ID 是事务开启时 InnoDB 分配的,其大小决定了事务开启的先后顺序,因此我们可以通过 ID 的大小关系来决定版本记录的可见性;
    1. 如果被访问版本的 trx_id 小于 m_ids 中的最小值 up_limit_id,说明生成该版本的事务在 ReadView 生成前就已经提交了,所以该版本可以被当前事务访问。
    2. 如果被访问版本的 trx_id 大于 m_ids 列表中的最大值 low_limit_id,说明生成该版本的事务在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。需要根据 Undo Log 链找到前一个版本,然后根据该版本的 DB_TRX_ID 重新判断可见性。
    3. 如果被访问版本的 trx_id 属性值在 m_ids 列表中最大值和最小值之间(包含),那就需要判断一下 trx_id 的值是不是在 m_ids 列表中。如果在,说明创建 ReadView 时生成该版本所属事务还是活跃的,因此该版本不可以被访问,需要查找 Undo Log 链得到上一个版本,然后根据该版本的 DB_TRX_ID 再从头计算一次可见性;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。
    4. 此时经过一系列判断我们已经得到了这条记录相对 ReadView 来说的可见结果。此时,如果这条记录的 delete_flag 为 true,说明这条记录已被删除,不返回。否则说明此记录可以安全返回给客户端。

    参考

    MySQL InnoDB MVCC 机制的原理及实现


    你的鼓励也是我创作的动力

    打赏地址

  • 相关阅读:
    diary and html 文本颜色编辑,行距和其它编辑总汇
    bash coding to changeNames
    virtualbox ubuntu 网络连接 以及 连接 secureCRT
    linux 学习6 软件包安装
    linux 学习8 权限管理
    vim 使用2 转载 为了打开方便
    ubuntu
    linux 学习15 16 启动管理,备份和恢复
    linux 学习 14 日志管理
    linux 学习 13 系统管理
  • 原文地址:https://www.cnblogs.com/yangsanchao/p/13062908.html
Copyright © 2011-2022 走看看