zoukankan      html  css  js  c++  java
  • Mysql 事务隔离级别

    在MySQL的众多存储引擎中,只有InnoDB支持事务,所有这里说的事务隔离级别指的是InnoDB下的事务隔离级别。

    一、事务的基本要素(ACID)

    1. 原子性(Atomicity);事务开始后所有操作,要么全部做完,要么全部不做,不能停滞在中间环节。
    2. 一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏。
    3. 隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
    4. 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

    二、事务的并发问题

    1. 脏读:事务B修改数据但未提交,事务A读数据,然后B回滚,则A读到的是脏数据。
    2. 不可重复读:事务A第一次读取数据,事务B修改数据提交,事务A第二次读数据,两次数据不一致。
    3. 幻读:事务A update表的全部行,事务B插入一行,事务A就会发现表中还有未修改的行。(一般加间隙锁)

    三、MySQL事务隔离级别

    事务隔离级别 脏读 不可重复读 幻读
    读未提交 会 
    读已提交 不会
    可重复读 不会 不会
    串行话 不会 不会 不会

    查看mysql的默认事务隔离级别“show global variables like ‘tx_isolation’; ”

    数据库的锁是加在数据行对应的索引上的

     =======================悲观锁方向=========================================

    四、InnoDB 行锁模式

    Innodb的行锁模式有以下几种:共享锁,排他锁,意向共享锁(表锁),意向排他锁(表锁),间隙锁。

    1.共享锁

    又称读锁,读取操作创建的锁。一旦上锁,任何事物无法对其修改,但可以并发读取数据,也可以对此数据再加共享锁。

    2.排他锁

    又称写锁,如果事务对数据A加上排他锁后,则其他事物不可并发读取数据,也不能再对A加任何类型的锁。获准排他锁的事务既能读取数据,又能修改数据。

    在MySQL InnoDB中,UPDATE/INSERT/DELETE操作都会自动加排他锁,普通的SELECT语句不会加任何锁,如果想加锁,可以使用下面方式

    SELECT * FROM table_name WHERE id = 1 LOCK IN SHARE MODE; -- 显式加共享锁
    SELECT * FROM table_name WHERE id = 1 FOR UPDATE;         -- 显式加排他锁

    3.意向锁 (数据库自动帮加)

    InnoDB为了让表锁和行锁共存而使用了意向锁。(意向锁均为表级锁)

    事务A既然锁住了某一行,其他事务就不可能修改这一行。这与”事务B锁住整个表就能修改表中的任意一行“形成了冲突。所以,没有意向锁的时候,行锁与表锁共存就会存在问题!

    意向共享锁:表示事务准备给数据行加入共享锁(行读锁S), 先加意向共享锁IS

    意向排他锁:事务准备给数据行加入排他锁(行写锁X),先加意向排他锁IX

    事务A在申请行写锁之前,数据库会自动给事务A申请表的意向排他锁,当事务B申请表写锁时,因为表上已经有意向排他锁,所以B申请的写锁会被阻塞。

     意向锁相互兼容,因为IX、IS只是表明申请更低层次级别元素(比如 page、记录)的X、S操作

     4.记录锁、间隙锁、临键锁、意向插入锁

    =================================乐观部分===============================

    MVCC

    Multi-Version Concurrency Control 即多版本并发控制,是为了解决读-写冲突而出现的。

    在MySQL中,多版本并发控制是InnoDB存储引擎实现读已提交和读未提交,隔离级别的具体方式。读未提交总是读取最新数据行,无需使用MVCC;可串行化需要对所有读取的行都加锁,单纯使用MVCC无法实现。

    MVCC一般用两种实现方式,InnoDB采用的是后者

    • 实时保留数据的一个或者多个历史版本
    • 在需要时通过undo日志构造出历史版本

    InnoDB为每个记录行都实现了三个隐藏字段

    6字节的事务ID(DATA_TRX_ID)标记了最新更新这条记录的事务id

    7字节的回滚指针  (RAR_ROLL_PTR)指向当前及录像的rollback segment 的undo log记录,找之前版本的数据就是通过这个指针

    一个6字节的DB_ROW_ID字段包含一个行ID,当插入新行时,该行ID会单调增加。如果 InnoDB自动生成聚簇索引,索引包含行ID值。否则,该 DB_ROW_ID列不会出现在任何索引中。

    另外,每条记录的头信息(record header)里都有一个专门的bit(deleted_flag来表示当前记录是否已经被删除

    更新字段时会进行如下操作

    用排他锁锁定该行

    记录redo log

    把该行修改前的值复制到undolog,即上图中下面的行。。

    修改当前行的值,填写事务编号,回滚指针指向undo log刚刚copy的行

    select 

    • InnoDB只查找版本号小于等于当前事务版本的数据行,这样可以确保数据行要么是在开始之前已经存在 了,要么是本事务自身插入或修改过的
    • 行的删除版本号 要么未定义,要么大于当前事务版本号,这样可以确保事务读取到的行,在事务开始之前未被删除。

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

    delete  InnoDB为删除的每一行保存当前事务版本号作为事务ID

    update InnoDB为插入一行新纪录,保存当前系统版本号作为行版本号, 同事保存当前系统版本号到原来的行作为行删除标识符

    对于READ_COMMITTED 

    读提交是,读事务每次都读取undo log中最近的版本,因此每次都能读取到最新的数据。

    MySQL的读一致性,是通过一个叫read view的结果来实现的。

    readview中维护了系统中活跃事务集合的快照。详见https://yq.aliyun.com/articles/560506

  • 相关阅读:
    ios原生项目内嵌u3d工程
    u3d内嵌H5游戏 设置cookie
    unity3d IL2CPP for android
    unity3D内嵌android项目
    Django 跨域问题
    tensorflow 调试tfdbg
    Cuda9.1+cunn7.1+Tensorflow1.7-GUP
    shader
    lua 中protobuf repeated 嵌套类 复合类型
    30岁的思考
  • 原文地址:https://www.cnblogs.com/chafanbusi/p/10657478.html
Copyright © 2011-2022 走看看