MySQL事务(4种事务隔离级别、脏写、脏读、不可重复读、幻读、当前读、快照读、MVCC、事务指标监控)

这篇具有很好参考价值的文章主要介绍了MySQL事务(4种事务隔离级别、脏写、脏读、不可重复读、幻读、当前读、快照读、MVCC、事务指标监控)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

声明测试表,供文章案例使用

CREATE TABLE `cs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `num` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

事务的分类

  • 显示事务:
    • read write:读写事务,默认模式,表示当前事务可以读写数据。
    • read only:只读事务,很少用,表示当前事务不能修改数据。
    • with consistent snapshot:一致性快照,在数据库事务中确保事务在执行过程中能看到一个事务开始时的一致数据库状态,避免被其他并发操作影响。
  • 隐式事务:不需要显示声明事务相关语句,autocommit是开启状态(默认值),每条DML和DDL的SQL语句都是一个独立的事务。

MySQL事务的4个特性:

  • 原子性(Atomicity):当前事务中的执行结果,要么全部执行成功,要么全部执行失败。
  • 一致性(Consistency):事务执行前后,数据库从一个合法(指符合业务预期)状态转换成另一个一合法状态。
  • 隔离性(Isolation):多个事务可以并发执行,各个事务之间的操作互相隔离互不干扰。
  • 持久性(Durability):无论事务提交还是回滚,都会持久化到磁盘中。

自动提交

自动提交(auto commit),指的是SQL语句执行完毕后自动将数据持久化到磁盘(刷盘)中。
显式的声明事务,或者声明set autocommit = 0;都可以关闭自动提交。

savepoint

  • 俗称保存点,是用于实现部分事务回滚的一种机制,需要确定从哪里开始回滚,就需要savepoint的标识来定位。
  • 回滚范围:从保存点开始到事务最后一条SQL,都会被回滚。
  • 适用场景:用于复杂的业务逻辑中,给出灵活可控的后悔药,降低事务回滚影响范围。
  • 注意:rollback to之后,不代表事务流程走完,还需要再次commit提交其它未回滚的事务。
  • 用法:
    savepoint 保存点名:创建一个 Savepoint,并为其指定一个名称。
    rollbackto savepoint 保存点名;:将事务回滚到指定的 Savepoint。
    release savepoint 保存点名;:释放指定的 Savepoint。
    示例:
start transaction;
insert into cs(num) values(1);
savepoint insert_1;
insert into cs(num) values(2);
savepoint insert_2;
insert into cs(num) values(3);
savepoint insert_3;
insert into cs(num) values(4);
savepoint insert_4;
rollback to insert_2;
commit;
发现1,2数据被插入。

事务的隐式提交

在上一个事务没提交或回滚时,运行下一个事务,则上一个事务自动提交。

start transaction;
insert into cs(num) values(1);
insert into cs(num) values(2);
start transaction;
insert into cs(num) values(3);
insert into cs(num) values(4);
commit;
成功插入1,2,3,4。

4种隔离级别

  • 读未提交(Read Uncommitted):最低级别的隔离,事务中的修改即使未提交也能被其他事务看到,可能导致脏读、不可重复读和幻读问题。
  • 读已提交(Read Committed):保证一个事务提交后对其他事务可见,避免了脏读,但可能会导致不可重复读和幻读问题。
  • 可重复读(Repeatable Read):保证在同一事务内多次读取数据时,数据保持一致,避免了不可重复读问题,但仍可能出现幻读。
  • 串行化(Serializable):最高级别的隔离,通过对读取的数据添加共享锁或排他锁来确保事务之间的隔离性,避免了脏读、不可重复读和幻读问题,但可能会影响并发性能。

表格从上到下,越来越高可用,但是性能越来越低。

隔离级别 是否解决脏读 是否解决不可重复读 是否解决幻读 是否加锁
读未提交
读已提交
可重复读
串行化

查看或设置MySQL隔离级别

  • 查看:select @@transaction_isolation; 或者 show variables like 'transaction_isolation;'
  • 设置:set session transaction_isolation = 'read-uncommitted/read-committed/repeatable-read/serializable';
    注意隔离级别是回话级别的,所以无法set glboal。

MySQL会发生什么读?

因为mysql默认隔离级别是可重复读(Repeatable Read),所以只会发生幻读情况,脏读和可重复度不会发生,除非改事务隔离级别。

脏写(不允许发生)

  • 简介:一个事务修改某些数据时,另一个事务在未提交的情况下也修改了这些数据,引起的导致数据的不一致性。
  • 危害:造成数据在并发情况下严重不一致。
  • 演示:试不出来,脏写这么严重的bug,是不允许发生的情况。

脏读(读未提交隔离级别会发生)

  • 简介:一个事务尚未commit(提交,刷盘,持久化),却读取了事务修改后的值,引起数据读取不准确的情况。
  • 危害:事务还未提交就被读取了,该事务成功提交还好,要是回滚了,会造成读取数据不一致的问题。
  • 演示:因为脏读是读未提交(Read Uncommitted)才会发生的情况,所以要降低MySQL的隔离级别。
步骤 会话A 会话B 备注
1 set session transaction_isolation = 'read-committed'; set session transaction_isolation = 'read-committed'; 设置事务的隔离级别为读未提交
2 select @@transaction_isolation; select @@transaction_isolation; 检查隔离级别是否设置成功
3 select num from cs where id = 20; #20 start transaction;
update cs set num = 20 where id = 40;
会话A num的初始值为20
4 select num from cs where id = 20; #40 / 会话B并未commit,此时会话A中num的值为40,发生脏读现象
5 / rollback 结束本次事务
6 select num from cs where id = 20; #20 / num恢复为20

不可重复读(读未提交、读已提交隔离级别会发生)

  • 简介:在事务A中读取某些数据,然后在事务B中修改这些数据,此时事务A读取这些数据还未发生变化,但是事务B提交后,并在事务A在未结束事务的前提下,那些数据发生了变化,不可重复读不是禁止读动作,而是重复读数据不一致。
    一句话概括,在同一个事务中,受其它事务提交的影响,读取同一数据两次得到的结果不一致的现象。
  • 危害:破坏了事务内数据的准确性,例如事务内的SQL有自增自减的逻辑,如果事务内的初始值受其他事物提交从而发生变化,那么这是个巨大的问题。
  • 演示:因为不可重复读是读已提交(Read Committed)才会发生的情况,所以要降低MySQL的隔离级别。
步骤 会话A 会话B 备注
1 set session transaction_isolation = 'read-uncommitted'; set session transaction_isolation = 'read-uncommitted'; 设置事务隔离级别为读已经提交
2 select @@transaction_isolation; select @@transaction_isolation; 检查隔离级别是否设置成功
3 start transaction; start transaction; 双方开启事务
4 select num from cs where id = 20; #20 select num from cs where id = 20; #20 两个会话中num的值为20
5 update cs set num = 40 where id = 20; select num from cs where id = 20; #20 会话A将数据更新为40,此时会话B查询的值仍为20
6 commit select num from cs where id = 40; #40 会话A提交事务,会话B仍在事务中,但是得到的值变成了40,发生了不可重复读
7 / commit 结束事务

幻读(读未提交、读已提交、可重复读隔离级别会发生)

  • 简介:同一个事务里前后查询两次相同范围的数据,后一次查询查询到了前一次看不到的东西,就好像出现了"幻影"一样。(注意,如果把会话B的insert改为delete导致的数据减少,不算幻读,算不可重复读)。
  • 危害:没有充分的做好数据隔离,数据一致性存在问题。
  • 演示:mysql 的默认隔离级别为REPEATABLE-READ,所以大概率不用调整隔离级别。
步骤 会话A 会话B 备注
1 select @@transaction_isolation; select @@transaction_isolation; 检查隔离级别是否是REPEATABLE-READ
2 start transaction; start transaction; 双方开启事务
3 select * from cs; select * from cs; 两个事务查看,都只有id为20的一条数据
4 insert into cs (id,num) values(21,21); select * from cs; 会话B查询,仍旧只有id为20的一条数据
5 commit / 会话A提交事务
6 / select * from cs; 即使会话A提交了事务,会话B查询仍旧无法搜索到会话A插入的数据,起始这一步已经幻读了,但是mysql不表明是幻读,所以到第7步测试
7 / insert into cs (id,num) values(21,21); 因为会话B select查不到id为21的数据,所以插入id相同的数据,但是报错1062 - Duplicate entry '21' for key 'PRIMARY'
8 / rollback; 回滚以结束事务流程

如何解决幻读?

  • 或者使用串行化的隔离级别。在串行化隔离级别下,也会隐式的添加行(X)锁。
  • 添加间隙锁,可以避免幻读。
  • mysql 的默认隔离级别为REPEATABLE-READ,又称为RR,通过MVCC的机制,如果对数据进行快照读,正因为读取的不一定第最新的数据,所以可以防止幻读(注意不是解决幻读),如果是当前读(最近数据),那么仍旧会发生幻读现象。

当前读

当前读读的就是数据最新的记录,需要保证当前读的数据不能被修改,修改了就不是最新的记录了(脏写),因此需要加锁,select for update、select lock in share mode以及DML(insert、update、delete)获取的数据都是当前读的数据。

快照读

快照读顾名思义,读取的就是由MVCC Read View控制的undo log的数据,不加锁,所以是读取是非阻塞的。不加锁的select都属于快照读。如果当前事务的隔离级别是串行化,那么快照读也变成了当前读。
举个例子:常用的navicat,查看一个表,事务提交前的insert或update语句,表格内仍旧显示的原数据,则用的快照读。

MVCC

MVCC(Multi-Version Concurrency Control)是 MySQL 中一种实现事务隔离的机制,用于处理数据库事务并发访问时可能出现的读写冲突。事务的四种隔离级别,就是通过MVCC机制提供的底层支撑。
MVCC三板斧:隐藏字段、Undo log(存放历史版本)、Read view(版本控制)

MVCC解决的是读已提交和可重复读级别的并发控制。
因为读未提交,就算事务未提交,可以直接读取最新的数据(脏读),相当于当前读,那就不分快照读和当前读了。
串行化的隔离级别,强制事务串行执行,也不存在快照读和当前读的区分,因为读取的都是事务执行过后的最新数据。

事务各项指标监控

查看 InnoDB 存储引擎中当前活动的事务信息。文章来源地址https://www.toymoban.com/news/detail-838026.html

SELECT * FROM information_schema.innodb_trx;

trx_id                         事务的唯一标识符。
trx_state                      事务的状态,如 RUNNING、LOCK WAIT、ROLLING BACK 等。
trx_started                    事务启动的时间。
trx_requested_lock_id          请求的锁的标识符。
trx_wait_started               等待锁的开始时间。
trx_weight                     事务的权重,用于死锁检测。
trx_mysql_thread_id            MySQL 线程 ID。
trx_query                      与事务相关的 SQL 查询语句。
trx_operation_state            事务内部操作的状态。
trx_tables_in_use              事务使用的表的数量。
trx_tables_locked              事务锁定的表的数量。
trx_lock_structs               事务内部使用的锁结构数量。
trx_lock_memory_bytes          用于事务锁定的内存字节数。
trx_rows_locked                事务锁定的行数。
trx_rows_modified              事务修改的行数。
trx_concurrency_tickets        用于事务并发控制的票数。
trx_isolation_level            事务的隔离级别。
trx_unique_checks              是否启用了唯一性检查。
trx_foreign_key_checks         是否启用了外键约束检查。
trx_last_foreign_key_error     最后一个外键错误信息。
trx_adaptive_hash_latched      是否适应性哈希被锁定。
trx_adaptive_hash_timeout      适应性哈希锁定超时次数。
trx_is_foreign_key_with_check  是否用于外键约束检查。
trx_is_foreign_key             是否用于外键约束。

到了这里,关于MySQL事务(4种事务隔离级别、脏写、脏读、不可重复读、幻读、当前读、快照读、MVCC、事务指标监控)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【MYSQL】事务隔离级别

    脏读 一个事务正在对一条记录做修改,在这个事务完成并提交前,另一个事务也来读取同一条记录,读取了这些未提交的“脏”数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象的叫作’脏读’(Dirty Reads)。 例子:事务A修改了一条数据1状态

    2024年01月19日
    浏览(41)
  • MySQL的事务隔离级别

    目录 事务隔离级别的概念 脏读(Dirty Read): 不可重复读(Non-Repeatable Read): 幻读(Phantom Read): 读未提交(Read Uncommitted) 读未提交隔离级别的特点 示例 优势和劣势 读已提交(Read Committed) 读已提交隔离级别的特点 示例 优势和劣势 可重复读(Repeatable Read) 可重复读隔

    2024年02月09日
    浏览(50)
  • Mysql 索引 、事务、隔离级别

    目录 索引(index) 1.为什么要有索引? 2.引入索引的代价 3.索引的操作 4.索引的使用场景 5.索引的底层原理 事务 (transaction) 事物的回滚是怎么做到的 事物的四大特性 并发执行事务带来的问题 隔离级别 索引是一种为了加快数据库查询(操作)速度而引入的一种手段,需要占用额

    2024年01月20日
    浏览(59)
  • 【MySQL】事务与隔离级别详解

    事务就是一组DML语句组成 ,这些语句在逻辑上存在相关性,这一组DML语句要么全部成功,要么全部失败,是一个整体(原子性)。例如买票操作,上层看来是一个单纯的买票操作,但是下层却需要一条或多条SQL语句来完成转账操作,这一组SQL是一个整体,被称为事务。事务还

    2024年02月15日
    浏览(50)
  • MySQL的事务特性、事务特性保证和事务隔离级别

            事务是指要么所有的操作都成功执行,要么所有的操作都不执行的一组数据库操作。 一、MySQL提供了四个事务特性,即ACID:          1. 原子性(Atomicity) :一个事务中的所有操作要么全部提交成功,要么全部回滚失败,保证事务的原子性。          2. 一

    2024年02月03日
    浏览(41)
  • mysql不同隔离级别事务插入数据

    面试中问到了相关问题,做下问题记录 问题是这样的,数据库默认隔离级别下,事务A插入一条数据,没有提交,事务B插入一条数据,提交,表id为自增,如果表是空表,事务A和事务B的id分别是多少。 2.1.1 打开一个mysql窗口,事务A 执行代码块 2.1.2 打开另一个窗口,事务B 执

    2024年02月11日
    浏览(53)
  • 【MySql】MySql事务隔离级别与一致性

    MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行 一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题,可以

    2024年02月10日
    浏览(42)
  • MySQL - 并发控制与事务的隔离级别【头歌】

    目录 相关知识 并发操作可能产生的数据不一致性 MySQL的事务隔离级别 示例 第一关:并发控制与事务的隔离级别 编程要求 测试说明 代码如下 第二关:读脏 任务描述 相关知识 读脏 读脏产生的原因 编程要求 代码如下: 第三关:不可重复读 任务描述 相关知识 不可重复读

    2024年02月09日
    浏览(50)
  • 幻读与不可重复读的区分

            幻读重点在于数据 是否存在 。原本不存在的数据却真实的存在了,这便是幻读。         在同一个事务中,第一次读取到结果集和第二次读取到的结果集不同。引起幻读的原因在于另一个事务进行了 INSERT 操作。         不可重复读重点在于数据 是否被改

    2024年02月07日
    浏览(39)
  • MySQL5-事务隔离级别和锁机制

    ❤️ 个人主页:程序员句号 🚀 支持水滴:点赞👍 + 收藏⭐ + 留言💬+关注 🌸 订阅专栏:MySQL性能调优 原创博文、基础知识点讲解、有一定指导意义的中高级实践文章。 认真或有趣的技术分享。 MySQL性能优化专栏 1.MySQL性能优化1-MySQL底层索引结构 2.MySQL2-Explain详解 3.MySQL

    2024年02月07日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包