MySQL事务
事务特性
原子性(Atomicity)
事物的整个过程如原子操作一样,最终要么全部成功,或者全部失败,这个原子性是从最终结果来看的,从最终结果来看这个过程是不可分割的。
一致性(Consistency)
一个事物必须使数据库从一个一致状态转换到另一个一致状态。
隔离性(Isolatoin)
一个事物的执行不能被其他事务干扰。即一个事物内部的操作及使用的数据对并发的其他事物是隔离的,并发执行的各个事务之间不能互相干扰。
事务隔离级别
读未提交:read uncommitted
在读未提交隔离级别下,事务可以读取到其他事务未提交的数据。这种隔离级别可能会导致脏读、不可重复读和幻度的问题。脏读是指一个事务读取了另一个事务未提交的数据,而这些数据可能会被回滚,从而导致读取到的数据不一致。(并发场景下事务A修改数据但是没有提交事务,但是在事务B中能读到事务A修改后的数据,事务A可能会回滚事务)
读已提交:read committed
在读已提交隔离级别下,事务值能读取到其他事务已经提交的数据,从而避免了脏读问题。然而,不可重复读和幻读问题仍然可能发生。不可重复读是指一个事务中多次读取同一个数据时,结果可能不同,因为其他事务可能在此期间修改了数据。(并发场景下事务A修改数据并且提交后,事务B中能读到事务A修改后提交事务的数据,能读取到事务A提交前和提交后两种状态数据,即不可重复读)
可重复读:repeatable read
可重复读是MySQL InnoDB存储引擎的默认隔离级别。在这种隔离级别下,同一事物的多次读取结果是一致的,除非数据被该事务本身修改,可重复读可以防止脏读和不可重复读,但幻读问题仍然可能发生。InnoDB通过使用MCVV(多版本并发控制)和Next-Key Lock(行锁和间隙锁的结合)来解决幻读问题。(并发场景下事务A修改数据,事务B查询的数据是事务A未修改前的并且事务A提交后事务B查询的数据还是事务A未修改前的,即可重复读)
串行化:serializable
串行化是最高的隔离级别,完全遵循ACID的隔离性要求。在这种隔离级别下,所有事物依次逐个执行,完全避免了脏读、不可重复读和幻读问题。然而,串行化隔离级别的并发性能较低,通常只在特殊情况下使用。
持久性(Durability)
一个事务一旦提交,他对数据库中的数据的改变就应该是永久性的。当事务提交后,数据持久化到硬盘,修改是永久性的。
隐式事务
事务自动开启、提交或回滚,比如insert、update、delete语句,事务的开启、提交或回滚由mysql内部自动控制。 产看变量autocommit是否开启了自动提交
show variables like 'autocommit';显式事务
事务需要手动开启、提交或关闭,由开发者自己控制。
set autocommit=0;|begin;|start transaction;
commit|rollblack;脏读
定义
A事务正在修改数据但未提交,此时事务B去读取此条数据,B事务读取的是未提交的数据。A事务回滚
解决方法
- 事务隔离级别设置为:read committed
- 读取时加共享锁(select...lock in share mode),事务提交才会释放锁,修改时加排他锁(select...for update)。加排他锁后,不能对该条数据再加锁,其他事务既不能查询也不能更改数据。mysql InnoDB引擎默认的修改数据语句,update、delete、inesrt都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁,如果加排他锁可以使用select...for update语句,如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁,共享锁下其他用户可以并发读取,查询数据。但不能修改、增加、删除数据。资源共享。
不可重复读
定义
A事务中两次查询同一条数据的内容不同,B事务间在A事务两次读取之间更改了此条数据
解决办法
- 事务隔离级别设置为:Repeatable read
- 读取数据加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事务修改该数据,不管数据在事务中读取多少次数据都是一致的,避免了不可重复读问题
幻读
定义
- 说法一:事务 A 根据条件查询得到了 N 条数据,但此时事务 B 删除或者增加了 M 条符合事务 A 查询条件的数据,这样当事务 A 再次进行查询的时候真实的数据集已经发生了变化,但是A却查询不出来这种变化,因此产生了幻读。
- 说法二:幻读并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:A事务select 某记录是否存在,结果为不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。产生这样的原因是因为有另一个事务往表中插入了数据。
可重复读
定义
并发场景下事务A修改数据,事务B查询的数据是事务A未修改前的并且事务A提交后事务B查询的数据还是事务A未修改前的,但是事务A增加删除数据,事务B查询不到,这是幻读
解决办法
加间隙锁
MVCC
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 备注 |
|---|---|---|---|---|
| 读未提交(READ UNCOMMITTED) | 允许 | 允许 | 允许 | 会读到未提交的数据,出现脏读、不可重复读、幻读(隔离级别最低,并发性能高) |
| 读已提交(READ COMMITTED) | 禁止 | 允许 | 允许 | 不会读到未提交的数据,会出现不可重复读、幻读问题(锁定正在读取的行) |
| 可重复读(REPEATABLE READ) | 禁止 | 禁止 | 允许 | 会出现幻读(锁定读取的所有行) |
| 串行化(SEIALIZABLE) | 禁止 | 禁止 | 禁止 | 保证所有的情况不会发生(锁表) |
| 读问题 | 解释 | 隔离级别 |
|---|---|---|
| 脏读 | 事务A读取了事务B未提交的数据,若事务B回滚,事务A读取到无效数据 | 读未提交 |
| 不可重复读 | 事务A读取了事务B提交的数据 | 读已提交 |
| 幻读 | 事务A多次查询相同范围数据,结果行数不一致,事务B插入行或删除行 | 可重复读 |
| 读未提交 | 允许脏读、不可重复读、幻读 | 读未提交 |