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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 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 不能保证没有幻读,需要加锁。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
103 43
|
2月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1650 14
|
3月前
|
存储 Oracle 关系型数据库
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
从基本特性、技术选型、字段类型、事务提交方式、SQL语句、分页方法等方面对比Oracle和MySQL的区别。
566 18
Oracle和MySQL有哪些区别?从基本特性、技术选型、字段类型、事务、语句等角度详细对比Oracle和MySQL
|
2月前
|
SQL 关系型数据库 MySQL
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
尼恩,一位40岁的资深架构师,通过其丰富的经验和深厚的技術功底,为众多读者提供了宝贵的面试指导和技术分享。在他的读者交流群中,许多小伙伴获得了来自一线互联网企业的面试机会,并成功应对了诸如事务ACID特性实现、MVCC等相关面试题。尼恩特别整理了这些常见面试题的系统化解答,形成了《MVCC 学习圣经:一次穿透MYSQL MVCC》PDF文档,旨在帮助大家在面试中展示出扎实的技术功底,提高面试成功率。此外,他还编写了《尼恩Java面试宝典》等资料,涵盖了大量面试题和答案,帮助读者全面提升技术面试的表现。这些资料不仅内容详实,而且持续更新,是求职者备战技术面试的宝贵资源。
阿里面试:MYSQL 事务ACID,底层原理是什么? 具体是如何实现的?
|
2月前
|
存储 关系型数据库 MySQL
RR隔离级别在MySQL中的实现与幻读问题探讨
【10月更文挑战第3天】在数据库管理系统中,事务隔离级别是确保数据一致性和并发性能的关键要素。MySQL作为广泛使用的关系型数据库管理系统,支持多种事务隔离级别,其中可重复读(Repeatable Read,简称RR)是其默认隔离级别。本文将深入探讨RR隔离级别在MySQL中的实现原理,以及RR隔离级别下幻读问题的产生与解决方案。
85 2
|
2月前
|
关系型数据库 MySQL 数据库
MySQL数据库:基础概念、应用与最佳实践
一、引言随着互联网技术的快速发展,数据库管理系统在现代信息系统中扮演着核心角色。在众多数据库管理系统中,MySQL以其开源、稳定、可靠以及跨平台的特性受到了广泛的关注和应用。本文将详细介绍MySQL数据库的基本概念、特性、应用领域以及最佳实践,帮助读者更好地理解和应用MySQL数据库。二、MySQL
123 5
|
3月前
|
SQL 关系型数据库 MySQL
MySQL基础:事务
本文详细介绍了数据库事务的概念及操作,包括事务的定义、开启、提交与回滚。事务作为一组不可分割的操作集合,确保了数据的一致性和完整性。文章还探讨了事务的四大特性(原子性、一致性、隔离性、持久性),并分析了并发事务可能引发的问题及其解决方案,如脏读、不可重复读和幻读。最后,详细讲解了不同事务隔离级别的特点和应用场景。
150 4
MySQL基础:事务
|
3月前
|
关系型数据库 MySQL 数据库
深入理解MySQL数据库隔离级别
深入理解MySQL数据库隔离级别
125 1
|
4月前
|
人工智能 小程序 关系型数据库
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
本文以热门游戏《黑神话:悟空》为契机,深入浅出地解析了数据库事务的四种隔离级别:读未提交、读已提交、可重复读和串行化。通过具体示例,展示了不同隔离级别下的事务行为差异及可能遇到的问题,如脏读、不可重复读和幻读等。此外,还介绍了在MySQL中设置隔离级别的方法,包括全局和会话级别的调整,并通过实操演示了各隔离级别下的具体效果。本文旨在帮助开发者更好地理解和运用事务隔离级别,以提升数据库应用的一致性和性能。
143 2
【MySQL】黑悟空都掌握的技能,数据库隔离级别全攻略
|
2月前
|
SQL 关系型数据库 MySQL
【MySQL】索引和事务
【MySQL】索引和事务
55 0