【MySQL回顾】事务篇
什么是事务
事务是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
事务是逻辑上的一组操作,要么都执行,要么都不执行。
事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
MySQL 事务主要用于处理操作量大,复杂度高的数据。
比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!
事务的特性
一般来说,事务是必须满足4个条件(ACID):
原子性(Atomicity):
事务是最小的执行单位,不允许分割
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency)
- 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性(Isolation)
- 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性(Durability)
- 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
并发事务带来的问题
并发处理事务时,经常回操纵相同的数据处理不同的事务,可能会产生以下问题:
- 脏读(dirty read):当一个事务访问数据并对其进行修改后,还未提交到数据库时另一个事务访问了改数据,读到的数据是未经更新的数据(脏数据),依据脏数据进行的操作可能有误。
- 丢失修改(Lost to modify):两个事务同时访问一个数据时,都对数据做出了修改,第一个事务所修改的数据丢失。
- 不可重复读(Unrepeatable read):在一个事务(A)内两次读取数据的过程中另一个事务(B)访问并修改了该数据,使得 A 读取到的两次数据不一致。
- 幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读的区别:
- 不可重复读重点在修改
- 幻读重点在添加或删除
事务隔离级别
SQL标准定义了四个事务隔离级别:
READ-UNCOMMITTED(读取未提交):
最低的事务隔离级别,允许读取尚未提交的数据
READ-COMMITTED(读取已提交):
允许读取并发已提交的事务
REPEATABLE-READ(可重复读):
对同意字段读取的结果是一致的,除非是被本身事务所修改
SERIALIZABLE(可串行化):
最高隔离级别,所有事务依次执行,事物之间不能互相干扰
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
MySQL InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读)。
我们可以通过命令
SELECT @@transaction_isolation;
来查看当前的事务隔离级别。这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 REPEATABLE-READ(可重读)事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 REPEATABLE-READ(可重读) 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的**SERIALIZABLE(可串行化)**隔离级别。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是**READ-COMMITTED(读取提交内容):**,但是你要知道的是InnoDB 存储引擎默认使用 REPEATABLE-READ(可重读)并不会有任何性能损失。
InnoDB 存储引擎在 分布式事务 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
实际操作
我们可以通过下面的命令来设置隔离级别。
1 | SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] |
控制并发的语句:
START TARNSACTION
|BEGIN
:显式地开启一个事务。COMMIT
:提交事务,使得对数据库做的所有修改成为永久性。ROLLBACK
:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
参考
javaGuide: https://snailclimb.gitee.io/javaguide/#/docs/database/