mysql事务

事务

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

  • 读未提交
    一个事务可以读取到另一个事务未提交的修改。这会带来脏读、幻读、不可重复读问题。(基本没用)
  • 读已提交
    一个事务只能读取另一个事务已经提交的修改。其避免了脏读,但仍然存在不可重复读和幻读问题。
  • 可重复读
    同一个事务中多次读取相同的数据返回的结果是一样的。其避免了脏读和不可重复读问题,但幻读依然存在。
  • 串行化
    事务串行执行。避免了以上所有问题。

MVCC

MVCC的全称是“多版本并发控制”。这项技术使得InnoDB的事务隔离级别下执行一致性读操作有了保证,换言之,就是为了查询一些正在被另一个事务更新的行,并且可以看到它们被更新之前的值。这是一个可以用来增强并发性的强大的技术,因为这样的一来的话查询就不用等待另一个事务释放锁。这项技术在数据库领域并不是普遍使用的。一些其它的数据库产品,以及mysql其它的存储引擎并不支持它。以下是他的写入规则:

  • 插入数据
    create_version 记录插入数据的事务id,delete_version为空;
  • 删除数据
    delete_version记录删除数据的事务id,create_version 为空
  • 修改数据
    将修改数据视为“删除旧数据,插入新数据”的组合。即先将原来数据复制一份,原有数据的delete_version记录修改数据的事务id,create_version为空。复制出来的新数据的create_version记录修改数据的事务id,delete_version为空。

mysql mvcc

在InnoDB中,给每行增加两个隐藏字段来实现MVCC,一个用来记录数据行的创建时间,另一个用来记录行的过期时间(删除时间)。在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。

于是乎,默认的隔离级别(REPEATABLE READ)下,增删查改变成了这样:

  • SELECT
    读取创建版本小于或等于当前事务版本号,并且删除版本为空或大于当前事务版本号的记录。这样可以保证在读取之前记录是存在的。
  • INSERT
    将当前事务的版本号保存至行的创建版本号
  • UPDATE
    新插入一行,并以当前事务的版本号作为新行的创建版本号,同时将原记录行的删除版本号设置为当前事务版本号
  • DELETE
    将当前事务的版本号保存至行的删除版本号

快照读和当前读

  • 快照读:读取的是快照版本,也就是历史版本

  • 当前读:读取的是最新版本

普通的SELECT就是快照读,而UPDATE、DELETE、INSERT、SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE是当前读。

锁定读

在一个事务中,标准的SELECT语句是不会加锁,但是有两种情况例外。SELECT ... LOCK IN SHARE MODE 和 SELECT ... FOR UPDATE。

  SELECT ... LOCK IN SHARE MODE

  给记录假设共享锁,这样一来的话,其它事务只能读不能修改,直到当前事务提交

  SELECT ... FOR UPDATE

  给索引记录加锁,这种情况下跟UPDATE的加锁情况是一样的

一致性非锁定读

 consistent read (一致性读),InnoDB用多版本来提供查询数据库在某个时间点的快照。如果隔离级别是REPEATABLE READ,那么在同一个事务中的所有一致性读都读的是事务中第一个这样的读读到的快照;如果是READ COMMITTED,那么一个事务中的每一个一致性读都会读到它自己刷新的快照版本。Consistent read(一致性读)是READ COMMITTED和REPEATABLE READ隔离级别下普通SELECT语句默认的模式。一致性读不会给它所访问的表加任何形式的锁,因此其它事务可以同时并发的修改它们。

分析

  • 一致性读保证了可用重复读
    利用MVCC实现一致性非锁定读,这就有保证在同一个事务中多次读取相同的数据返回的结果是一样的,解决了不可重复读的问题

  • 间隙锁防止了幻读
    利用Gap Locks和Next-Key可以阻止其它事务在锁定区间内插入数据,因此解决了幻读问题
    综上所述,默认隔离级别的实现依赖于MVCC和锁,再具体一点是一致性读和锁。

posted @   clouderzheng  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示