mysql事务隔离分类及实现

事务简介

事务支持是在存储引擎层实现的。MySQL 是一个支持多引擎的系统,但并不是所有的引擎都支持事务。此处以 InnoDB 为例,进行剖析。

提到事务,不得不说ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性)。本章主要剖析隔离性有哪几类,以及如何实现。

SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )

  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
  • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成(释放锁),才能继续执行。

“读未提交”隔离级别下直接返回记录上的最新值即可;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。而“可重复读”和“读提交”隔离级别则需要通过一种“快照”的方式实现,这两种隔离级别的实现方式几乎一样,此处以可重复读为例进行剖析。

数据更新及回滚过程

  • InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的
  • 每行数据是可以有多个版本的。每次事务更新数据的时候,都会生成一个新的数据版本,并在数据版本中记录 row trx_id = transaction id 。
  • 每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

注意事项:

  • 这些回滚段,在数据库中完全不可能用到的时候会被清理掉。完全不可能用到,即不存在与数据版本对应的存活事务。
  • 所以长事务可能导致回滚段数据堆积过多,不能及时清理。即使清理掉 ,文件也不会缩小。

如何实现事务隔离级别为可重复读呢?

在清楚了数据如何更新和回滚的基础上,我们来考虑如何利用 数据版本,事务id,回滚日志 来实现可重复读。

大体解决方案如下

  • 以我启动事务的时刻为准,如果一个数据版本是在我启动之前生成的,就认;如果是我启动以后才生成的,就不认,并通过回滚找“上一个版本”。当然,如果“上一个版本”也不可见,那就得继续往前找。
  • 如果是这个事务自己更新的数据,它自己是要认的。

具体的实现方案

  • 首先把整个过程分为启动前,启动时,启动后三个时间段,如下图

  • 在事务中,数据是否应该被认,如何判断?如下图,一行记录的所有版本数据被分成了三段,这就是我们建立的快照。需要注意的是中间段,如果数据版本对应的事务id,是启动时活跃的事务id,则不可见。

  • 在事务中,一个查询的逻辑如下图所示。目的就是,确保查询的数据,一定是事务启动前已经提交的数据,让整个事务中同样的查询每次结果都一致。实现方式就是对事务id进行对比。

  • 在事务中,自己更新的数据,自己是认的。特别需要注意,更新操作,都是基于最新版本数据的。 即先查询得到最新版本数据,再写入修改后的数据。

读提交与可重复读最主要的区别

  • 在可重复读隔离级别下,只需要在事务开始的时候打一个快照,之后事务里的其他查询都共用这个快照;
  • 在读提交隔离级别下,每一个语句执行前都会重新打一个快照。

MySQL 的事务启动方式

  • 显式启动事务语句, begin 或 start transaction。配套的提交语句是 commit,回滚语句是 rollback。
  • set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个 select 语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行 commit 或 rollback 语句,或者断开连接。有些客户端连接框架会默认连接成功后先执行一个 set autocommit=0 的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。
  • 因此,我会建议你总是使用 set autocommit=1, 通过显式语句的方式来启动事务。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值