2、MySQL事务隔离

什么是事务?

保证一致性,保证一组数据库操作,要么全部成功,要么全部失败。
CAID(Atomicity,Consistency,lsolation,Durability):

  • 原子性:要么全部成功commit,要么全部失败rollback;
  • 一致性:rollback后的数据和之前一样;
  • 隔离性:事务和事务之间不干扰;
  • 持久性:事务一旦提交就不能改了;

事务的隔离性与隔离级别

四种事务隔离级别

  • 读未提交(read uncommitted):一个事务还没提交时,他做的变更就能被其他事务看到;
  • 读提交(read committed):一个事务提交后,他做的变更就会被其他事务看到;
  • 可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。
  • 串行化(serializable):对同一行记录,读写都会加锁。当读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

Mysql视图概念

  • view;用查询语句定义的虚拟表,语法create view...
  • InnoDB在实现MVCC时用到的一致性视图,即consistent read view,用于支持RC(Read Committed读提交)和RR(Repeatable Read可重复读)隔离级别实现的。

视图创建时间

数据库会创建一个视图,访问的时候以视图的逻辑结果为准。

  • 读未提交:直接返回记录最新值,没有视图概念;
  • 读提交:视图是在每个SQL语句开始执行的时候创建的;
  • 可重复读:视图是在事务启动时创建的,整个事务存在期间都用这个视图;
  • 串行化:直接用加索的方式来避免并行访问;

开启事务方式

  • 查看当前事务:
    show variables like 'tx_isolation';(或者transaction-isolation)
  • 开启事务:
    transaction-isolation(或tx_isolation,与数据库版本有关)参数设置为READ-COMMINTTED(读提交模式)

隔离级别操作

  • 查看当前会话隔离级别:select @@tx_isolation;
  • 查看系统当前隔离级别:select @@global.tx_isolation;
  • 设置当前会话隔离级别:set session transaction isolation level read committed;
  • 设置系统当前隔离级别:set global transaction isolation level read committed;

事务隔离实现——可重复读

  • 每条记录在更新时都会同时记录一条回滚操作。记录上的最新值,通过回滚操作可以得到前一个状态的值。
  • 数据库多版本并发控制(MVCC):同一条记录在系统中可以存在多个版本。
  • 回滚日志(undo log)何时删除?
    当没有事务再需要用到这些回滚日志时(即当系统里没有比这个回滚日志更早的read-view的时候),回滚日志就会被删除。
  • 为什么尽量不要使用长事务
    a、 长事务意味着系统里面会存在很老的事务视图。由于这些事务可能会访问数据库中的数据,所以在这个事务提交前,数据库里面他可能用到的回滚记录都必须保留,导致大量占用存储空间。
    b、长事务占用锁资源。

事务启动方式

  • 显示启动事务语句,begin或start transaction。提交语句时commit,回滚rollback。
  • set outcommit=0;将自动提交关闭,执行select语句就会打开事务,直到主动执行commit或rollback才提交事务。
    建议使用:
    set outcommit = 1;使用begin显示启动事务,执行commit提交事务。(执行commit work and chain,用于提交事务并自动启动下一个事务,省去下一次begin的开销,建议使用)。
    查找长事务语句(查找持续时间超过60s的事务):
    select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60;

事务启动时机

  • 第一种:begin/start transaction,一致性视图是在执行第一个快照读语句时创建的。
  • 第二种:start transcation with consistent snapshot,执行这个命令时创建的。

“快照”在MVCC工作方式

  • 每个事务有唯一的事务ID,transcation id;在事务开始时向InnoDB引擎申请的;

  • 每行数据有多个版本;每次事务更新数据时,都会生成一个新的数据版本,把transcation id赋值给这个数据版本的事务ID,记为row trx_id;旧版本保留,通过新版本和回滚日志可以得到旧版本。

    U1、U2、U3为undo log(回滚日志);V1、V2、V3并不是物理存在的,而是根据当前版本和undo log计算出来。

InnoDB如何定义数据“快照的”——可重复读、读提交模式

InnoDB为每个事务构造了一个数组,用来保存这个事务启动瞬间,当前正在“活跃”(启动但未提交)的所有事务ID。数组里面事务ID最小值记为“低水位”,当前系统里已经创建过的事务ID的最大值加1记为高水位。这个视图数组和高水位就组成了当前事务的一致性视图(read-view)。

对于当前事务的启动瞬间来说,一个数据版本的row trx_id,有一下几中可能:

  • 如果在绿色部分,表示这个版本是已提交的事务或当前事务自己生成的,这个数据是可见的;
  • 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是不可见的;
  • 如果落在黄色部分,分两种:
    1、若row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
    2、若不在数组中,表示这个版本是已经提交了的事务生成的,可见。

一个数据版本,对于一个事务视图来说,除了自己的更新总是可见外,有三种情况:

  • 版本未提交,不可见;
  • 版本已提交,但是在视图创建后提交的,不可见;
  • 版本已提交,而且是在视图创建前提交的,可见。

更新数据如何实现

  • 更新数据都是先读后写的,而这个读只能读当前的值,称为“当前读”(current read)。
  • 查询语句加锁也是当前读。语句后加上lock in share mode或for update。

事务的可重复读如何实现

可重复读的核心就是一致性图(consistent read);而事务更新数据时只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

读提交和可重复读逻辑的区别:

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都公用这个一致性视图;
  • 在都提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。
posted @ 2021-11-06 17:26  kevin_cy  阅读(87)  评论(0编辑  收藏  举报