写点什么

MySQL-InnoDB- 事务

  • 2022 年 4 月 23 日
  • 本文字数:1448 字

    阅读完需:约 5 分钟

事务 ACID 特性

原子性(Atomicity):最小的工作单元,整个工作单元要么一起提交成功,要么全部失败回滚。


一致性(Consistency):事务中操作的数据及状态改变是一致的,即写入资料的结果必须完全符合预设的规则,不会因为出现系统意外等原因导致状态的不一致。


隔离型(Isolation):一个事务所操作的数据在提交之前,对其他事务的可见性设定(一般设定为不可见)。


持久性(Durability):事务所做的修改就会永久保存,不会因为系统意外导致数据的丢失。

事务并发带来了哪些问题

脏读


比如 user 表中有一条用户数据,执行了如下操作:


  1. 事务 B 更新 id=1 的数据,age 更新为 18,不提交事务

  2. 事务 A 查询 id=1 的数据

  3. 事务 B 回滚刚才的更新操作


这个时候,事务 A 中查询出的 id=1 的数据,age 的值是 16 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 还是 18?

不可重复读


比如 user 表中有一条用户数据,执行了如下操作:


  1. 事务 A 查询 id=1 的数据

  2. 事务 B 更新 id=1 的数据,age 更新为 18,并提交事务

  3. 事务 A 再次查询 id=1 的数据


这个时候,事务 A 两次查询出的 id=1 的数据,age 的值是 16 还是 18?

幻读


比如在 user 表中执行了如下操作:


  1. 事务 A 查询 age>15 的数据

  2. 事务 B 新增一条数据,age=22,并提交事务

  3. 事务 A 再次查询 age>15 的数据


这个时候,事务 A 两次查询出的数据,数量是 1 条还是 2 条?

事务四种隔离级别

SQL92 ANSI/ISO 标准http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt


Read Uncommitted(未提交读)?--未解决并发问题


事务未提交对其他事务也是可见的,脏读(dirty read)


Read Committed(提交读)?--解决脏读问题


一个事务开始之后,只能看到自己提交的事务所做的修改,不可重复读(non repeatable?read)


Repeatable Read(可重复读)?--解决不可重复读问题


在同一个事务中多次读取同样的数据结果是一样的,这种隔离级别未定义解决幻读的问题


Serializable(串行化)?--解决所有问题


最高的隔离级别,通过强制事务的串行执行

InnoDB 引擎对隔离级别的支持程度


事务隔离级别的并发能力:未提交读 > 已提交读 > 可重复读 > 串行化


InnDB 引擎默认的事务隔离级别是可重复读(Repeatable Read),在该级别中它把幻读的问题也解决了。InnDB 中事务隔离级别通过锁、MVCC 实现。


通过如下语句查看 InnoDB 的默认事务隔离级别:


/* 全局、当前会话的隔离级别 */SELECT @@global.tx_isolation, @@tx_isolation;



通过如下语句设置 InnoDB 的事务隔离级别:


/* 设置全局隔离级别 /set global transaction isolation level read committed;/ 设置当前会话的隔离级别 */set session transaction isolation level read committed;


接下来我们来测试一下 InnoDB 的默认事务隔离级别(Repeatable Read)是否解决了脏读、不可重复读、幻读的问题。


数据准备:


CREATE TABLE user (id int(11) NOT NULL,name varchar(32) NOT NULL,age int(11) NOT NULL,PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


insert into user (id, name, age) values('1','Ada','16');

是否解决了脏读的问题?


开启两个 MySQL 客户端,模拟事务 A 和事务 B 的操作,执行步骤如下:


  1. 事务 B 开启手动事务,更新 id=1 的数据,age 更新为 18,不提交事务

  2. 事务 A 查询 id=1 的数据

  3. 事务 B 回滚刚才的更新操作


图中的数字是执行步骤,通过下图可以看出事务 A 的执行结果是 16,InnDB 的默认事务隔离级别完美的解决了脏读的问题。


是否解决了不可重复读的问题?


开启两个 MySQL 客户端,模拟事务 A 和事务 B 的操作,执行步骤如下:

用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
MySQL-InnoDB-事务_Java_爱好编程进阶_InfoQ写作社区