MySQL
1、事务概述
1.1 概念
事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行行逻辑单元;
是一个最小的不可分割的工作单元,能保证一个业务的完整性;
事务中可能包含一个或多个sql语句,这些语句要么都执行,要么都不执行。
1.2 事务的语法
- start transaction;/ begin;
- commit; 使得当前的修改确认
- rollback; 使得当前的修改被放弃(回滚)
2、事务的ACID特性
2.1 原子性(Atomicity)
事务的原子性是指事务必须是一个原子的操作序列单元。表示事务内的全部操作为一个整体,要么全部成功,要么全部失败。不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
为了实现原子性,需要通过日志:将所有对数据的更新操作都写入日志,如果一个事务中的一部分操作已经成功,但以后的操作,由于断电/系统崩溃/其它的软硬件错误而无法继续,则通过回溯日志,将已经执行成功的操作撤销,从而达到“全部操作失败”的目的。
2.2 一致性(Consistency)
事务的一致性是指系统从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态。而事务具备ACID里C的特性是说通过事务的AID来保证我们的一致性。C是目的,AID都是手段。
知乎上有个回答也是写的蛮好的,大家可以看看:id 莺歌一笑
2.3 隔离性(Isolation)
事务的隔离性是指在并发环境中,并发的事务是互相隔离的。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间,如果在一个事务中要查看数据所处的状态,要么是另外一个并发事务修改它之前的状态,要么是另一个事务修改它之后的状态,事务不会查看中间状态的数据。
一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务是不能互相干扰的。
2.4 持久性(Duration)
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机等故障。只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。
3、事务并发引起的问题
-
脏读:读取到了了没有提交的数据, 事务A读取了了事务B更更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
-
不可重复读:同一条命令返回不同的结果集(更新).事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了了更新并提交,导致事务A多次读取同一数据时,结果不一致。
-
幻读:重复查询的过程中,数据就发生了量的变化(insert, delete)
3.1 事务隔离级别
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(READ_UNCOMMITTED) | 允许 | 允许 | 允许 |
读已提交(READ_COMMITTED) | 禁止 | 允许 | 允许 |
可重复读(REPEATABLE_READ) | 禁止 | 禁止 | 可能会 |
顺序读(SERIALIZABLE) | 禁止 | 禁止 | 禁止 |
查看当前会话中的事务隔离级别
-- mysql 8前
select @@tx_isolation;
-- mysql 8后
select @@transaction_isolation;
a. 读未提交(READ_UNCOMMITTED)
读未提交,该隔离级别允许脏读取,其隔离级别是最低的。换句话说,如果一个事务正在处理某一数据,并对其进行了更新,但同时尚未完成事务,因此还没有提交事务;而以此同时,允许另一个事务也能够访问该数据。
– MySQL设置隔离级别读未提交
set session transaction isolation level read uncommitted;
脏读示例:
在事务A和事务B同时执行时可能会出现如下场景:
余额应该为1500元才对。请看T5时间点,事务A此时查询的余额为0,这个数据就是脏数据,他是事务B造成的,很明显是事务没有进行隔离造成的。
b. 读已提交(READ_COMMITTED)
读已提交是不同的事务执行的时候只能获取到已经提交的数据。这样就不会出现上面的脏读的情况了。但是在同一个事务中执行同一个读取,结果不一致。
– MySQL设置隔离级别 读已提交 READ_COMMITTED
set session transaction isolation level read committed;
不可重复读示例:
可是解决了脏读问题,但是还是解决不了可重复读问题。
事务A其实除了查询两次以外,其它什么事情都没做,结果钱就从1000变成0了,这就是不可重复读的问题。
c. 可重复读(REPEATABLE_READ)
可重复读就是保证在事务处理理过程中,多次读取同一个数据时,该数据的值和事务开始时刻是一致的。(自己事务提交后才可以读取更新的值)因此该事务级别限制了不可重复读和脏读,但是有可能出现幻读的数据。
– MySQL设置隔离级别 可重复读 REPEATABLE_READ
set session transaction isolation level repeatable read;
幻读:幻读就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。
诡异的更新事件:
d. 顺序读(SERIALIZABLE)
顺序读是最严格的事务隔离级别。它要求所有的事务排队顺序执行,即事务只能一个接一个地处理,不能并发。
– MySQL设置隔离级别 顺序读 SERIALIZABLE
set session transaction isolation level SERIALIZABLE;
幻读和不可重复读两者区别:
1.不可重复读:A事务在执行过程中,B事务对数据进行了修改或删除,导致A两次读取的数据不一致(这里的不一致是指某一条或多条数据的内容前后不一致,但数据条数相同);
不可重复读重点在于update(锁行即可解决)
2.幻读:A事务在执行过程中,B事务新增了符合A事务要查询的数据,导致A两次读取的数据不一致;
幻读重点在于insert和delete(需要锁表解决)
所以说不可重复读和幻读最大的区别,就在于如何通过锁机制来解决他们产生的问题。
4、不同的隔离级别的锁的情况
- 读未提交(RU): 有行级的锁,没有间隙锁。它与RC的区别是能够查询到未提交的数据。
- 读已提交(RC):有行级的锁,没有间隙锁,读不到没有提交的数据。
- 可重复读(RR):有行级的锁,也有间隙锁,每次读取的数据都是一样的,并且没有幻读的情况。
- 序列列化(S):有行级锁,也有间隙锁,读表的时候,就已经上锁了
5、隐式提交
DQL:查询语句DML:写操作(添加,删除,修改)
DDL:定义语句(建库,建表,修改表,索引操作,存储过程,视图)
DCL:控制语言(给⽤用户授权,或删除授权)
DDL(Data Define Language):都是隐式提交。
隐式提交:执行这种语句相当于执行commit; DDL。