事务的ACID特性
A:atomicity :原子性
C:consistency :一致性
I:isolation : 隔离性
D:durability :持久性
原子性:一个事务内的操作时不可分割的,即要么全部执行成功,要么全部执行失败回滚到初始状态
一致性:应用系统从一个正确的状态,到另外一个正确的状态(AID三个特性是保证C特性,假设列a有约束不小于0,那么在事务中将列a的值修改为-1,那么执行的时候将会报错,事务回滚)
隔离性:一个事务内的操作能否被另外一个事务看见的程度,不同的隔离级别下,情况不一样
持久性:事务一旦提交,那么事务内所做的操作就会被永久性保留下来。
MyISAM引擎
不支持事务
InnoDB引擎
支持事务,共有四种隔离级别:读未提交,读已提交,可重复读,串行化
默认隔离级别是可重复读且事务自动提交,可通过set autocommit = 0,修改当前会话事务不自动提交
不同级别下的事务又会引发这几种问题:脏读,幻读,不可重复读
不同级别事务会引起的问题如下表:(Y-会引起,N-不会引起)
InnoDB 中事务的实现是通过锁来实现的,采用“一致性非锁定读”的机制提高了并发性。
一致性非锁定读通过多版本并发控制(MVCC)实现,表示当前行如果被加了排它锁,其他事务在读取该记录时,其实读取的是历史快照数据。
| 脏读 | 不可重复读 | 幻读 | |
|---|---|---|---|
| 读未提交(READ-UNCOMMITTED) | Y | Y | Y |
| 读已提交(READ-COMMITTED) | N | Y | Y |
| 可重复读(REPEATABLE-READ) | N | N | Y |
| 串行化(SERIALIZABLE) | N | N | N |
脏读
当前事务读取到其他事务未提交的数据。
幻读
当前事务在未提交之前,多次执行同样的查询sql,查询出的结果条数不一样,侧重在于结果集有新增或删除
不可重复读
当前事务在未提交之前,多次执行同样的查询sql,查询的结果不一样,侧重在于结果数据更新
假设有以下表ttt,,结构如下:
| id | str |
|---|---|
| 1 | 111 |
| 2 | 222 |
| 3 | 333 |
读未提交
在该隔离级别下,当前事务可以读取到其他事务为提交的数据,会引发脏读,幻读,不可重复读三种问题。例如:脏读问题
- 分别在两个窗口a,b开启事务
- 窗口a执行 select * from ttt where id = 1; 结果集为id=1,str=111
- 窗口b执行 update ttt set str = 'aaa';
- 窗口a执行 select * from ttt where id = 1; 结果集为id=1,str=aaa
读已提交
在该隔离级别下,当前事务可以读取到其他事务已提交的数据,会引发不可重复读,幻读问题。
例如:不可重复读问题
- 分别在两个窗口a,b开启事务
- 窗口a执行 select * from ttt where id = 1; 结果集为id=1,str=111
- 窗口b执行 update ttt set str = 'aaa';
- 窗口a执行 select * from ttt where id = 1; 结果集为id=1,str=111
- 窗口b执行 commit;
- 窗口a执行 select * from ttt where id = 1; 结果集为id=1,str=aaa
可重复读
在该隔离级别下,当前事务前后读取的数据结果条数可能不一致,即幻读。例如:
- 分别在两个窗口a,b开启事务
- 窗口a执行 select * from ttt ; 结果集为id=1,2,3,str=111,222,333
- 窗口b执行 delete from ttt where id=1;
- 窗口a执行 select * from ttt ; 结果集为id=1,2,3,str=111,222,333
- 窗口b执行 commit;
- 窗口a执行 select * from ttt ; 结果集为id=2,3,str=222,333
串行化
在该隔离级别下,当前事务读取到的数据前后一致,但并发性能最低。