# 前言
事务概念
- 事务是一种逻辑处理机制,由一个有限的数据库操作序列构成。主要用于处理操作量大、复杂度高的数据。
- 在
MySQL
中,只有Innodb
引擎才支持事务,作用于insert
、update
、delete
语句。
为什么使用事务?
场景举例: 提现功能、下单功能、充值功能等。
本文提前准备工作
- 需要你连接
mysql
服务, 例: mysql -u root -p- 提前创建一张用户表以及预设一些数据
CREATETABLE`user`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'用户的ID',`user_name`varchar(140)NOTNULLDEFAULT'0'COMMENT'姓名',`age`int(3)NOTNULLDEFAULT'0'COMMENT'年龄',`is_del`enum('YES','NO')DEFAULT'NO',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=1DEFAULTCHARSET=utf8 COMMENT='用户表';INSERTINTO`user`(`id`,`user_name`,`age`,`is_del`)VALUES(1,'Chon',28,'NO');INSERTINTO`user`(`id`,`user_name`,`age`,`is_del`)VALUES(2,'Leslie',18,'NO');INSERTINTO`user`(`id`,`user_name`,`age`,`is_del`)VALUES(3,'Sam',38,'NO');INSERTINTO`user`(`id`,`user_name`,`age`,`is_del`)VALUES(4,'ALam',48,'NO');
一、事务的四大特性
事务四大特性(ACID): **原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)**。
1.1 原子性(Atomicity)
**原子性是指 事务作为整体被执行,是不可被分隔的单位,包含在其中的数据库语句,执行成功后,将执行结果持久化,如果发生错误,将会被
回滚
到事务开始前的状态,不可能停滞在中间某个环节或执行部分操作。**
场景举例: A 账户共有 1000元 人民币, 本次消费订单共计支付 200元 , 如果这时突然断电或服务器崩溃, 导致扣款成功但没有生成 订单信息, 这就发生了错误, 如果使用 事务 , 扣款与生成订单都成功时, 才算执行成功。
1.2 一致性(Consistency)
一致性指事务开始之前和完成以后,数据库的完整性约束没有被破坏。
- 数据库字段要求为整型,不可能存进一个字母。
- 假如你跟发小玩玻璃球,5 个人一共 100 个玻璃球,赢来输去,玩儿一下午,不考虑丢了,碎了,又去小卖部买等特殊情况,总是这 100 个玻璃球在手里转,不可能越玩儿越多,也不可能越玩儿越少,就是 100 个。
1.3 隔离性(Isolation)
隔离性指多个事务之间的执行是互不干扰的,一个事务不可能获取或操作到其它事务的内容。
- 但是
脏读
怎么来的,看本文下方的解释。
1.4 持久性(Durability)
持久性是指事务完成后,对数据库所作的更改会持久的保存在数据库之中,不会被回滚。
- 是不会被回滚,但
幻读
、不可重复读
怎么回事,看本文下方的解释。
二、事务隔离级别
隔离级别/影响脏读不可重复读幻读读未提交✅✅✅读已提交❎✅✅可重复读❎❎✅可串行化❎❎❎
✅ : 指在 特殊的操作流程中 会发生。
❎ : 指不会发生。
2.1 命令查看或设置隔离级别
2.1.1 查看默认全局事务隔离级别
# 第一种方式:showglobal variables like'%isolation%';# 第二种方式:select @@global.tx_isolation;
2.1.2 设置全局事务隔离级别
# 设置为 读未提交setglobaltransactionisolationlevelreaduncommitted;# 设置为 读已提交setglobaltransactionisolationlevelreadcommitted;# 设置为 可重复读setglobaltransactionisolationlevelrepeatableread;# 设置为 可串行化setglobaltransactionisolationlevelserializable;
2.1.3 查看当前会话事务隔离级别
# 第一种方式: showsession variables like'%isolation';# 第二种方式:select @@session.tx_isolation;# 第三种方式:select @@tx_isolation;
2.1.4 设置当前会话事务隔离级别
# 设置为 读未提交setsessiontransactionisolationlevelreaduncommitted;# 设置为 读已提交setsessiontransactionisolationlevelreadcommitted;# 设置为 可重复读setsessiontransactionisolationlevelrepeatableread;# 设置为 可串行化setsessiontransactionisolationlevelserializable;
2.2 读未提交 (read uncommitted)
读未提交: 查询语句不会加锁, 所有的事务都可以看到其他未提交事务的执行结果。
**读未提交可能会发生
脏读
。**
- 事务1 获取到了 事务2 中未提交的数据,发生了
脏读
。- 实例流程截图(请按照 红圈数字顺序 阅读):>
2.3 读已提交 (Read committed)
读已提交: 当前事务加记录锁, 但不会在事务之间加间隙锁, 事务之间可以看到其他已提交事务的执行结果。
- 事务1 获取到了 事务2 中已提交的数据。
- 实例流程截图(请按照 红圈数字顺序 阅读):>
2.4 可重复读 (Repeatable read)
可重复读: 是指多个事务并发读取时, 从事务的开始至结束, 本次事务内多次读取相同的数据, 都会返回一样的结果, 不会被其他事务的执行结果所影响。
**为
MySQL
默认隔离级别。**
**可重复读解决了
脏读
、
不可重复读
, 但可能会发生
幻读
。**
- 事务1 无法获取 事务2 中未提交与已提交的数据。
- 实例流程截图(请按照 红圈数字顺序 阅读):>
2.5 可串行化 (Serializable)
可串行化: 隐式将每个读语句加上共享锁, 通过强制事务排序, 使语句之间不会出现冲突。
**可串行化解决了
脏读
、
不可重复读
、
幻读
。**
因为加锁, 所以可能出现锁竞争, 从而导致业务的超时。
- 事务1 先开启事务, 事务2 的 修改语句 得需要等待 事务1 提交后才会执行。>
- 下图中可以看到, 事务1 提交后, 事务2
update
语句 在等待了 11.40 秒后, 才自动执行。>
三、事务之间的影响
3.1 脏读
简要说明: 一个事务中访问到了另一个事务中 未提交 的数据。
使用 读已提交、可重复读、可串行化 的事务隔离级别, 可解决
脏读
。
3.2 不可重复读
简要说明: 同一个事务中, 读取相同条件的数据, 返回的结果不一致。
使用 可重复读、可串行化 的事务隔离级别, 可解决
不可重复读
。
3.3 幻读
简要说明: 同一个事务中, 读取相同条件的数据, 返回的条数不一致。
使用 可串行化 的事务隔离级别, 可解决
幻读
。
3.4 情况分析
点我查看 - 可重复读隔离级别在哪种情况下会出现幻读
版权归原作者 Chon-Wang 所有, 如有侵权,请联系我们删除。