MySQL事务隔离级别的最佳实践(上)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: MySQL事务隔离级别的最佳实践(上)

事务

一组SQL语句组成的逻辑处理单元。

  • 原子性(Actomicity)
    事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行
  • 一致性(Consistent)

在事务开始和完成时,数据都必须保持一致状态

这意味着所有相关的数据规则都必须应用于事务的修改,以保持完整性

事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的

隔离性(Isolation)

一个事务所做的修改在最终提交前对其他事务不可见

持久性(Durability)

一旦事务提交,它对于数据的修改会持久化到DB

事务的问题

相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持可以支持更多的用户

但并发事务处理也会带来一些问题,主要包括以下几种情况

更新丢失(Lost Update)

当多个事务选择同一行,然后基于最初选定值更新该行时,由于事务隔离性,最后的更新覆盖了其他事务所做的更新.

例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改;

如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题

脏读(Dirty Reads)

一个事务正在对一条记录做修改,在该事务提交前,这条记录的数据就处于不一致状态。

这时,另一个事务也来读取同一条记录,读取了这些未提交的数据,例如: 早期版本、回滚。

不可重复读(Non-Repeatable Reads)

一个事务在读取某些数据,发现已经发生改变或某些记录已被删除。

不加锁时,其他事务的 UPDATE 或 DELETE 会影响查询结果。

幻读(Phantom Reads)

加锁后,不锁定间隙,其他事务可以 INSERT。

比如一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据。

很多人容易搞混不可重复读和幻读,这两者确实非常相似:

  • 不可重复读主要是多次读取一条记录,发现该记录中某些列值被修改过
  • 幻读主要是说多次读取一个范围内的记录(包括直接查询所有记录结果或做聚合统计), 发现结果不一致。一般指记录增多!记录的减少也算幻读!

事务并发下的异常

SQL-92标准中定义了如下异常:

  • 脏读(Dirty Read)
  • 不可重复读(Nnrepeatable Read)
  • 幻读(Phantom Read)
  • 比如说我们有个英雄表heros_temp,如下所示:


这张英雄表,我们会记录很多英雄的姓名,假设我们不对事务进行隔离操作,那么数据库在进行事务的并发处理时会出现怎样的情况?


第一天,小张访问数据库,正在进行事务操作,往里面写入一个新的英雄“吕布”:


SQL> BEGIN;

SQL> INSERT INTO heros_temp values(4, ‘吕布’);

当小张还没有提交该事务的时候,小李又对数据表进行了访问,他想看下这张英雄表里都有哪些英雄:


SQL> SELECT * FROM heros_temp;

这时,小李看到的结果如下:


你有没有发现什么异常?这个时候小张还没有提交事务,但是小李却读到了小张还没有提交的数据,这种现象我们称之为“脏读”。


那么什么是不可重复读呢?


第二天,小张想查看id=1的英雄是谁,于是他进行了SQL查询:


SQL> SELECT name FROM heros_temp WHERE id = 1;

运行结果:


然而此时,小李开始了一个事务操作,他对id=1的英雄姓名进行了修改,把原来的“张飞”改成了“张翼德”:


SQL> BEGIN;

SQL> UPDATE heros_temp SET name = ‘张翼德’ WHERE id = 1;

然后小张再一次进行查询,同样也是查看id=1的英雄是谁:


SQL> SELECT name FROM heros_temp WHERE id = 1;

运行结果:


这个时候你会发现,两次查询的结果并不一样。小张会想这是怎么回事呢?他明明刚执行了一次查询,马上又进行了一次查询,结果两次的查询结果不同。实际上小张遇到的情况我们称之为“不可重复读”,也就是同一条记录,两次读取的结果不同。


什么是幻读?


第三天,小张想要看下数据表里都有哪些英雄,他开始执行下面这条语句:


SQL> SELECT * FROM heros_temp;


这时当小张执行完之后,小李又开始了一个事务,往数据库里插入一个新的英雄“吕布”:


SQL> BEGIN;

SQL> INSERT INTO heros_temp values(4, ‘吕布’);

不巧的是,小张这时忘记了英雄都有哪些,又重新执行了一遍查询:


SQL> SELECT * FROM heros_temp;


他发现这一次查询多了一个英雄,原来只有3个,现在变成了4个。这种异常情况我们称之为“幻读”。


脏读:读到了其他事务还没有提交的数据。

不可重复读:对某数据进行读取,发现两次读取的结果不同,也就是说没有读到相同的内容。这是因为有其他事务对这个数据同时进行了修改或删除。

幻读:事务A根据条件查询得到了N条数据,但此时事务B更改或者增加了M条符合事务A查询条件的数据,这样当事务A再次进行查询的时候发现会有N+M条数据,产生了幻读。

事务隔离级别

在并发事务问题中,“更新丢失”应该完全避免,但防止更新丢失,并不能单靠数据库事务控制器,需需要应用程序对要更新的数据加必要的锁来解决。

因此,防止更新丢失应该是应用的责任。


脏读、不可重复读和幻读都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制。


数据库实现事务隔离的方式如下:


在读取数据前,对其加锁,防止其他事务对数据进行修改

不加任何锁,通过一定机制生成一个数据请求时间点的一致性数据快照,并用这个快照来提供一定级别(语句级或事务级)的一致性读取

从用户的角度,好像是数据库可以提供同一数据的多个版本,又称为数据多版本并发控制(MultiVersion Concurrency Control,MVCC)或多版本数据库

数据库的事务隔离级别越严格,并发副作用越小,但付出的代价也越大。因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”矛盾。


为解决“隔离”与“并发”的矛盾,ANSI SQL定义了4种隔离级别:

隔离级别/读数据一致性及允许的并发副作用 读数据一致性 脏读 不可重复读 幻读
未提交读(Read uncommitted) 最低级别,只能保证不读取物理上损坏的数据
已提交度(Read committed) 语句级
可重复读(Repeatable read) 事务级
可序列化(Serializable) 最高级别,事务级

隔离性用于防止数据库在并发时的数据不一致。

最严格时,可用串行化执行每个事务,事务之间相互独立,不存在并发。

但是在实际生产环境下,考虑到随着用户量的增多,会存在大规模并发访问,要求数据库有更高吞吐量,这时串行化无法满足数据库高并发访问需求,还要降低隔离标准,换取事务间的并发力。


有时需牺牲一定的正确性换取效率的提升,即需要通过设置不同的隔离等级,以便在正确性和效率之间进行平衡。同时,随着RDBMS种类和应用场景的增多,数据库的设计者需要统一对数据库隔离级别进行定义,说明这些隔离标准都解决了哪些问题。

事务隔离级别

脏读、不可重复读和幻读这三种异常情况,是在SQL-92标准中定义的,同时SQL-92标准还定义了4种隔离级别来解决这些异常情况。

解决异常数量从少到多的顺序(比如读未提交可能存在3种异常,可串行化则不会存在这些异常)决定了隔离级别的高低,这四种隔离级别从低到高:

读未提交(READ UNCOMMITTED,RU )

允许读到未提交的数据,这种情况下查询是不会使用锁的,可能会产生脏读、不可重复读、幻读,不能保证一致性,很少使用。


读已提交(READ COMMITTED,RC)

只能读到已经提交的内容,可以避免脏读的产生。

如果想避免不可重复读或幻读,就需要在SQL查询时编写加锁的SQL语句。

特点

  • 每次查询都会设置和读取自己的新快照
  • 仅支持基于行的 bin-log
  • UPDATE 优化
  • 半一致读(semi-consistent read)
  • 不可重复读
  • 幻读(Phantom)
    加锁后,不锁定间隙,其他事务可以 INSERT

锁定索引记录,而不锁定记录之间的间隙。

可重复读(REPEATABLE READ)

InnoDB默认的隔离级别。

保证同一事务在相同查询条件下两次查询得到的数据结果是一致的,可以避免不可重复读和脏读,但无法避免幻读。

原理

  • 使用事务第一次读取时创建的快照
  • 多版本技术

使用的锁

  • 使用唯一索引的唯一查询条件时,只锁定查找到的索引记录,但不锁定间隙
  • 其他查询条件, 会锁定扫描到的索引范围,通过间隙锁或next-key锁阻止其他会话在这个范围插值

可能的问题

InnoDB 不能保证没有幻读,需要加锁。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
5月前
|
SQL 关系型数据库 MySQL
MySQL锁机制:并发控制与事务隔离
本文深入解析了MySQL的锁机制与事务隔离级别,涵盖锁类型、兼容性、死锁处理及性能优化策略,助你掌握高并发场景下的数据库并发控制核心技巧。
|
6月前
|
存储 监控 Oracle
MySQL事务
MySQL事务具有ACID特性,包括原子性、一致性、隔离性和持久性。其默认隔离级别为可重复读,通过MVCC和间隙锁解决幻读问题,确保事务间数据的一致性和并发性。
MySQL事务
|
7月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
4月前
|
关系型数据库 MySQL 数据库
【赵渝强老师】MySQL的事务隔离级别
数据库并发访问时易引发数据不一致问题。如客户端读取到未提交的事务数据,可能导致“脏读”。MySQL通过四种事务隔离级别(读未提交、读已提交、可重复读、可序列化)控制并发行为,默认为“可重复读”,以平衡性能与数据一致性。
333 0
|
5月前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
223 0
|
7月前
|
安全 关系型数据库 MySQL
mysql事务隔离级别
事务隔离级别用于解决脏读、不可重复读和幻读问题。不同级别在安全与性能间权衡,如SERIALIZABLE最安全但性能差,READ_UNCOMMITTED性能高但易导致数据不一致。了解各级别特性有助于合理选择以平衡并发性与数据一致性需求。
220 1
|
8月前
|
关系型数据库 MySQL 数据库
MySQL报错:未知系统变量'tx_isolation'及隔离级别查询
记住,选择合适的隔离级别,就像是在风平浪静的湖面上找到适合的划船速度——既要快到能赶上午饭(性能),又不至于翻船(数据一致性问题)。
358 3
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
5304 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
SQL 关系型数据库 MySQL
京东面试:MySQL MVCC是如何实现的?如何通过MVCC实现读已提交、可重复读隔离级别的?
1.请解释什么是MVCC,它在数据库中的作用是什么? 2.在MySQL中,MVCC是如何实现的?请简述其工作原理。 3.MVCC是如何解决读-写和写-写冲突的? 4.在并发环境中,当多个事务同时读取同一行数据时,MVCC是如何保证每个事务看到的数据版本是一致的? 5.MVCC如何帮助提高数据库的并发性能?
京东面试:MySQL MVCC是如何实现的?如何通过MVCC实现读已提交、可重复读隔离级别的?
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
749 7
MySQL事务日志-Undo Log工作原理分析

推荐镜像

更多