首页 > 其他分享 >InnoDB 事务模型

InnoDB 事务模型

时间:2024-03-31 21:56:06浏览次数:11  
标签:事务 加锁 READ lock 模型 UPDATE 索引 InnoDB

参考资料

https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-transaction-model.html

ACID模型

ACID模型是一组数据库设计原则, 强调业务数据存储的可靠和关键型应用程序运行的稳定 。InnoDB存储引擎遵循了ACID设计,可以保证数据不会因软件崩溃和硬件故障等异常情况而丢失。其中ACID分别是

  • A : atomicity 原子性:指一个事务中的所有操作,要么全部完成,要么全部失败
  • C : consistency 一致性:指事务操作前和操作后,数据均满足一组约束,同时数据库保持一致性状态,只是从一个有效状态转移到另一个有效状态。以A、B两个账户互相转账为例,A、B两个账户总额为5000,那么不管他们之间怎么转账,两个账户的总额都是5000,这就是有效状态;同时A、B两个账户的余额不小于0,这就是满足约束。
  • I: : isolation 隔离性:指多个事务并行时,事务之间互相不影响
  • D : durability 持久性:指事务提交后,即使系统崩溃,数据仍然不会丢失

InnoDB 实现ACID模型所使用的一些组件工具

  • redo log:用于事务数据恢复,与持久性相关
  • undo log:用于事务回滚和一致性读,与原子性相关
  • MVCC 和 Lock:用于控制事务并发,与隔离性有关

事务隔离

隔离级别是一种设置,用于在多个事务同时进行更改和执行查询时微调性能与可靠性、一致性和结果可再现性之间的平衡。InnoDB提供了SQL 1992标准中描述的所有四种事务隔离级别:

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

REPEATABLE READ是InnoDB默认的隔离级别,但在实际应用中,READ COMMITTED使用会更加广泛。

InnoDB使用MVCC和锁策略支持各个事务隔离级别。使用READ COMMITTED隔离级别,可以最小化锁的开销,提高并发性能,尤其是在批量更新时。

在命令行或配置文件中使用 --transaction-isolation可配置全局事务隔离级别;也可以在连接MySQL时动态设置当前连接的隔离级别,单独配置将覆盖全局配置。

https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_transaction-isolation

并行事务问题

当并行事务操作同一个数据时,存在以下问题

脏读

指的是事务A读取了事务B修改了但还未提交的数据。如果事务B之后回滚了,事务A读取到的就是脏数据。

不可重复读

指的是在一个事务中,前后多次执行同一条查询语句(查询单个记录)时,查询到数据不一致的情况。在事务前后查询的间隙,如果数据被其它事务修改,就会产生不可重复读问题。

幻读

指的是,在一个事务中,前后多次查询符合条件的记录数量时,查询到记录数量不一致的情况。在事务A前后查询的间隙,如果事务B增加了一条符合事务A查询条件的记录,事务A中前后查询符合条件的记录数时就会产生幻读问题。

不同隔离级别下并行事务存在的问题

可以看到,性能开销最小的读未提交,所有并发问题都存在;性能开销最大的串行,解决了所有事务并发问题。

可重复读 REPEATABLE READ

在可重复读级别下,解决了脏读、不可重复读,并且很大程度上防止了幻读。加锁的基本单位是临键锁(有效防止幻读),进行一致性读、加锁读、新增数据时处理逻辑如下

  • 新增数据

进行Insert时,先针对要插入索引记录中的间隙申请插入意向锁,如果该间隙已经被加锁,则等待;若没被加锁则获得插入意向锁,然后插入数据。

  • 一致性读

解决不可重复读和脏读,事务中的普通读都是一致性读,并且一致性读是基于当前事务第一次查询时建立的快照。这表示在事务中执行普通读不会读取到未提交的数据,并且前后多次执行同一个普通读语句时,结果是一致的。有一个例外是,针对事务本身更新的数据,在更新之后进行的查询,获取的数据是最新的。

事务中第一次创建快照的时间点为:

  • start transaction启动事务后中第一次使用select语句
  • 启动事务时创建start transaction with consistent snapshot
  • 加锁读

很大程度上防止了幻读,事务中进行加锁读,如(SELECT with FOR UPDATE or LOCK IN SHARE MODE)、UPDATE和DELETE语句时,加锁策略取决于语句上的搜索条件

  • 对于唯一索引上的等值查询,有值时,只会锁定查询的记录本身。如select id where id = 2 for update,其中id为主键索引。如果有id等于2的数据时,这条语句只会锁定id=2的记录[2],不会锁定间隙;如果没有则会锁定最近的间隙,例如有1,3两条记录,则间隙锁区间为(1, 3)。
  • 对于其他的搜索条件,使用间隙锁或者临键锁来锁定扫描到的索引记录,阻止其他会话插入到临键锁所覆盖的间隙中。只在唯一索引上会使用间隙锁,因为唯一索引本身的约束就阻止了该记录的新增,无需重复锁定。

读提交 READ COMMITTED

在读提交隔离级别下,只解决了脏读问题,存在不可重复读和幻读问题,但提高了数据库并发性能。加锁的基本单位是记录锁,进行一致性读、加锁读、新增数据时处理逻辑如下

  • 新增数据

进行Insert时,不需要加插入意向锁,直接插入数据,通过page latch控制并发。

  • 一致性读

解决脏读,在事务中,每次普通SELECT都是一致性读。但是每次一致性读都会创建新的ReadView,然后再进行一致性读。这表示事务中进行普通SELECT不会读取到未提交的数据,但执行多个普通SELECT语句时,执行结果可能是不同的。

  • 加锁读

事务中进行加锁读,如(SELECT with FOR UPDATE or LOCK IN SHARE MODE)、UPDATE和DELETE语句时,只锁定记录本身,不会锁定索引间的间隙。由于加锁读时,只使用了记录锁,所以完全无法避免幻读。

READ COMMITTED隔离级别只支持基于row的binlog。如果使用READ COMMITTED和binlog format=MIXED,数据库将自动使用基于row的binlog。

可重复读和读提交加锁区别

在读提交隔离级别下

  • 对于UPDATE或DELETE语句,InnoDB只为更新或删除的行保留锁。MySQL评估WHERE条件后,将释放不匹配行的记录锁,这可以降低死锁的概率。
  • 执行UPDATE时,如果该行已经锁定,InnoDB会执行半一致性(semi-consistent)读,将该行最新提交的版本返回给MySQL,以便MySQL可以确定该行是否符合UPDATE的WHERE条件。如果符合,MySQL再次读取该行,InnoDB尝试对该行加x锁,若锁冲突,则等待加锁。

半一致性可以提高并发性能,但也可能导致并发更新冲突,需要使用乐观锁或者悲观锁来控制并发访问,确保在更新数据时避免出现冲突,从而保证数据的一致性和正确性。

例如,创建一个table,并新增数据。表中没有设置主键索引,所以会有一个内部的自增索引。在进行搜索时,索引扫描会使用这个隐藏的内部索引。

CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;

启动一个session A,执行update

# Session A
START TRANSACTION;
UPDATE t SET b = 5 WHERE b = 3;

启动一个session B,执行update

# Session B
UPDATE t SET b = 4 WHERE b = 2;

当使用默认的REPEATABLE READ隔离级别时,执行Update语句时,会首先对读取到的每一行添加x排他锁(如果有锁冲突则等待),然后再决定是否更新它,并且需要等到事务结束后才释放锁。因为第一个Update语句没有走索引,所以执行时会扫描隐藏索引上的全部记录,并将索引上的记录和间隙全部锁定,直到事务结束才释放。

x-lock(1,2); retain x-lock
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); retain x-lock
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); retain x-lock

第二个UPDATE语句在试图获取任一行的x锁时阻塞(因为第一次UPDATE保留了所有行和间隙的锁,而在REPEATABLE READ隔离级别时,需要先对扫描到的索引记录和间隙加锁,再进行更新,所以第二个UPDATE直接阻塞),直到第一次UPDATE提交或回滚后才继续执行

x-lock(1,2); block and wait for first UPDATE to commit or roll back

如果使用READ COMMITTED,执行UPDATE时,索引扫描记录后,先对扫描到的记录申请加X记录锁

  • 如果索引记录已经被其它事务加锁,则使用半一致性读,先去读取行的最新版本数据,根据where子句判断该行是否符合更新条件,符合则申请X记录锁;不符合则放弃该行。
  • 如果索引记录没有锁定,则先加X记录锁,然后读取该行数据,根据where子句判断该行是否符合更新条件,符合则更新,不符合则先释放该行的锁。

执行第一个UPDATE会对它读取的每一行获取x锁,并释放未修改的行上面的锁

x-lock(1,2); unlock(1,2)
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); unlock(3,2)
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); unlock(5,2)

执行第二个UPDATE语句。针对已锁定的行,InnoDB使用半一致性读,MySQL判断该行是否匹配where语句,如果匹配再去申请对该行加x锁;不匹配则直接放弃。针对未锁定的行,先加锁,再判断是否是需要更新的行,是则更新;不是则放弃。

x-lock(1,2); update(1,2) to (1,4); retain x-lock
x-lock(2,3); unlock(2,3)
x-lock(3,2); update(3,2) to (3,4); retain x-lock
x-lock(4,3); unlock(4,3)
x-lock(5,2); update(5,2) to (5,4); retain x-lock

读未提交 READ UNCOMMITTED

与READ COMMITTED类似,只是存在脏读问题。

串行化 SERIALIZABLE

与REPEATABLE READ类似,只是会隐式的将普通的SELECT转换为SELECT ... LOCK IN SHARE MODE。

标签:事务,加锁,READ,lock,模型,UPDATE,索引,InnoDB
From: https://www.cnblogs.com/cd-along/p/18107332

相关文章

  • InnoDB 行格式
    参考资料https://relph1119.github.io/mysql-learning-notes/#/mysql/疑问常常有如下疑问:往MySQL中新增的一行数据是怎么存储的?行溢出是什么?为什么说varchar字段最大可存储空间为65535字节?正确吗?行格式InnoDB中提供了四种行格式,Compact、Redundant、Dynamic和Comp......
  • EfficientNetV2:谷歌又来了,最小的模型,最高的准确率,最快的训练速度 | ICML 2021
     论文基于training-awareNAS和模型缩放得到EfficientNetV2系列,性能远优于目前的模型。另外,为了进一步提升训练速度,论文提出progressivelearning训练方法,在训练过程中同时增加输入图片尺寸和正则化强度。从实验结果来看,EfficientNetV2的效果非常不错。来源:晓飞的算法工程笔记......
  • InnoDB 内存结构
    参考资料https://dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.htmlhttps://relph1119.github.io/mysql-learning-notes/#/mysql/InnoDB内存结构内存结构如下图查看InnoDB运行状态SHOWENGINEINNODBSTATUS通过上述命令查看InnoDB运行时的状态信息BufferPool......
  • 一致性模型
    一致性模型模型Store:一个黑盒用以提供数据可用性,以及数据持久性A/B/C:三个相互独立的Process,对Store有读写操作一致性强一致性当A写入到Store后,之后的A,B,C的读操作都将返回最新值弱一致性当A写入到Store后,Store不能保证A,B,C的读操作都将返回最新值.最终一致......
  • 突破编程_C++_网络编程(OSI 七层模型(传输层))
    1传输层的功能与特点1.1传输层的功能传输层是OSI七层模型中的第四层,它位于网络层和应用层之间,起着承上启下的关键作用。以下是关于OSI传输层功能的详细讲解:一、提供可靠的数据传输服务传输层的主要任务是确保数据在源主机和目标主机之间可靠地传输。它通过一系列......
  • 【部分内容摘录】深度学习(人工智能):大模型的微调方法
    原文地址:http://www.cn-witmed.com/list/34/9555.html模型微调的基本思想是使用少量带标签的数据对预训练模型进行再次训练,以适应特定任务。在这个过程中,模型的参数会根据新的数据分布进行调整。这种方法的好外在于,它利用了预训练模型的强大能力,同时还能够适应新的数据分布。......
  • InnoDB 数据页
    参考资料https://relph1119.github.io/mysql-learning-notes/#/mysql/我们知道InnoDB管理存储空间的基本单位是页,一个页的大小默认是16KB。InnoDB为了不同的目的而设计了许多种不同类型的页,如changebufferpage、undologpage、indexpage。其中,IndexPage就是用于存放数......
  • 模型调优的艺术:超参数调整与集成方法
    目录1.前言2.超参数搜索策略2.1.网格搜索(GridSearch)2.2.随机搜索(RandomSearch)3.模型集成技术3.1.Bagging(BootstrapAggregating)3.2.Boosting4.实例:优化现有模型性能5.总结1.前言         模型调优是机器学习实践中至关重要的一环,它关乎模型能否在新......
  • delphi基于数据模型(data-model)JSON序列
    delphi基于数据模型(data-model)JSON序列需要DELPHI10.2以上版本才能支持。1)实现JSON序列/还原的泛型模板unitserialize;///<author>cxg2024-1-11</author>interfaceusessystem.Classes,System.SysUtils,System.JSON.Serializers;typeTSerial<T:record>......
  • 上海人工智能实验室大模型算法岗(实习)面经分享
    节前,我们星球组织了一场算法岗技术&面试讨论会,邀请了一些互联网大厂朋友、参加社招和校招面试的同学,针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。汇总合集:《大模型面试宝典》(2024版)发布!......