美文网首页
MySQL事务和隔离

MySQL事务和隔离

作者: 慧鑫coming | 来源:发表于2019-03-03 22:12 被阅读0次

    如何理解MySQL的事务?

    • 简单来说就是要保证一组数据库操作,要么全部成功,要么全部失败。MySQL中的事务支持是在引擎层实现的
    • 事务具有原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)四个特性。

    SQL标准的事务隔离级别包括:

    • 读未提交 read-uncommited
    • 读提交  read-commited
    • 可重复读 repeatable read
        一个事务执行过程中看到的数据,总是和这个事务启动时看到的数据是一致的。在可重复读隔离级别下,未提交的变更对其他线程也是不可见的。
    • 串行化  serializable
        对同一行记录,读会加“读锁”,写会加“写锁”,当出现读写冲突时,前后访问的事务必须等前一个事务执行完成,才能继续执行。

    查看隔离级别

    • 在MySQL客户端中输入show variables like 'transaction-isolation';,即可查看当前的隔离级别。

    MySQL中的2种“视图”

    • 一种是view,是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果,创建view的语法是create view ...,它的查询方法与表一样。
    • 另一种是consistent read view,它是InnoDB在实现MVCC时用到的一致性视图,用于支持RC(读提交)和RR(可重复读)隔离级别的实现。

    InnoDB隔离级别的实现

    • 事务启动时,数据库里会创建一个视图,访问的时候以视图的逻辑结果为准。
    • 可重复读隔离级别下,视图是在事务启动时创建的,整个事务存在期间都用这个视图。
    • 读提交隔离级别下,视图是在每个SQL语句开始执行的时候创建的。
    • 读未提交隔离级别下,直接返回记录上的最新值,没有视图。
    • 串行化隔离级别下,直接用加锁的方式避免并行访问。

    可重复读隔离级别的实现

    • 在可重复读隔离级别下,MySQL中每条记录在更新的时候都会记录一条回滚操作。记录上的最新值,通过回滚操作(undo log),都会得到前一状态的值。不同时刻启动的事务有不同的视图,即同一条记录在系统中可以存在多个版本,这就是数据库的MVCC(多版本并发控制)。
    • InnoDB里每个事务都有一个唯一的transaction id,它是事务开始的时候向InnoDB事务系统申请的,按申请顺序严格递增。
    • 而每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新的版本,并把本次事务的transaction id赋值给这个数据版本的事务ID,记为row trx_id。同时旧的数据版本要保留,并且在新的数据版本中,能有信息(undo log)可以直接拿到它。也就是说数据表中的同一行记录,可能存在多个版本(row),每个版本都有自己的row trx_id
    • MVCC的实现,InnoDB为每个事务构造一个数组,用来保存这个事务的启动瞬间,当前所有启动了,但还没提交的事务的ID
    • 一个数据版本,对于一个事务视图来说,除了自己的更新总是可见的以外,还有3种情况:
        1、版本未提交,不可见;
        2、版本已提交,但是是在视图创建后提交的,不可见;
        3、版本已提交,而且是在视图创建前提交的,可见。
      https://blog.csdn.net/syilt/article/details/107647007

    基于可重复读隔离的实现,说明为什么尽量不要使用长事务?

    • 长事务意味着系统里面会存在很老的事务视图,由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交前,数据库里面它可能用到回滚记录都必须保留,这就会导致大量占用存储空间。
    • MySQL5.5及以前版本,回滚日志(undo log)是和“数据字典”一起放在ibdata文件里的,即使长事务最终提交,回滚段被清理,ibdata文件也不会变小。
    • 注意,长事务不是“长连接”。

    MySQL事务的启动方式

    • 显示启动,begin;strat transaction;(并不是立即开启,而是执行第一条操作InnoDB表的语句时才是真正开启,提这点主要想说明它影响视图的出现时机;如果想马上启动一个事务,获得一个read view,可以使用start transaction with consistent snap shot;),配套的提交语句commit,回滚语句rollback,commit work and chain提交事务并自动开启下一个事务(节省再次执行begin语句的开销),此时一般是参数autocommit=1的情况。
    • 当set autocommit=0的时候,线程不会自动提交。此时,若只执行一个select语句,事务就已经启动了,并且不会自动提交。直到commit或rollback或断开连接。

    长事务查询

    • 查询持续时间超过60s的事务:
      select * from information_schema.innodb_trx where TIME_TO_SET(timediff(now(),trx_started)) > 60;

    事务更新时的版本控制逻辑

    • 更新数据都是先读后写,这个读只能是当前读(current read),即读当前的值(不管当前值得row trx_id是否大于本事务,都能读到);读到后会将自己修改后的数据和自己的事务ID赋给新的“当前值”。如果当前记录的行锁被其他事务占用,就需要进入锁等待状态。
    • 除update语句外,select语句如果加锁,也是当前读。有读锁(S锁,共享锁) lock in share mode;,写锁(X锁,排它锁)for update

    读提交和可重复读的主要区别

    • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都公用这个一致性视图。
    • 在读提交隔离级别下,每一个语句执行前都会重新计算出一个新的视图。

    相关文章

      网友评论

          本文标题:MySQL事务和隔离

          本文链接:https://www.haomeiwen.com/subject/ctrieqtx.html