#关系型数据库事务的四大特性(ACID)
- 原子性:事务是一个原子操作,其内部的执行过程,要么同时成功,要么同时失败;
- 一致性:事务开始之前的数据,和事务提交之后的数据必须保证一致性;举例:两张表存在外键约束,假如要删除主表中的一条记录,那么外键所在表中对应的记录也要一并删除;
- 隔离性:数据库提供一定的隔离机制,保证事务的执行过程尽可能不受并发操作的影响
- 持久性:事务提交后,它对数据的修改是持久化的(操作结果写入磁盘),即使在事务提交后系统发生了崩溃,事务对数据库所做的更改也不会丢失(mysql采用 redo log 实现);
#查看mysql的事务隔离级别
show variables like 'transaction_isolation';
#设置mysql的事务隔离级别
set transaction_isolation = 隔离等级;
隔离等级:
- READ-UNCOMMITTED:支持未提交读
- READ-COMMITTED:支持已提交读
- REPEATABLE-READ:支持可重复读
- SERIALIZABLE:支持可序列化
事务隔离级别 | 数据一致性等级 | 脏读 | 不可重复读 | 幻读 |
read uncommitted | 最低级 | 允许 | 允许 | 允许 |
read committed | 语句级 | 否 | 允许 | 允许 |
repeatable read | 事务级 | 否 | 否 | 允许 |
serializable | 事务级 | 否 | 否 | 否 |
#脏读诠释
事务A对记录1执行了修改操作,但未提交事务;
此刻,事务B读取了记录1(被事务A修改但未提交的记录1),并根据读到的结果进行了后续操作;
事务A因为某种原因导致事务回滚,记录1的变更被撤销;
由此可见,事务B读到了一个不正确的记录1,这将导致事务B的后续操作也都是不正确的;
#不可重复读诠释
其他事务的提交结果直接影响当前事务的执行;
举例:
记录1的 count 字段初始值为 1;
事务A读取记录1,并对记录1的 count 字段执行自增操作,未提交事务;
期间,事务B修改记录1的 count = 0,并提交事务;
事务A再次读取记录1,并对记录1的 count 字段执行自增操作,未提交事务;
期间,事务C修改了记录1的 count = 0,并提交事务;
事务A再次读取记录1,并对记录1的 count 字段执行自增操作,并提交事务;
由此可见,事务A的理想结果是 4,但实际结果却为 1;
#幻读诠释
事务在执行过程中,在相同的查询条件下,若两次查询的结果不一致,期间,事务本身又没有对记录进行修改,会认为出现幻觉;
假设表中数据为:
id | name | age |
1 | songy | 23 |
2 | luojy | 27 |
5 | guoqt | 26 |
6 | zeng | 34 |
事务A查询(非快照读,MVCC在REPEATABLE-READ隔离级别提供了Read View)表中满足 id >= 1 且 id <= 6 的记录,得到 4 条结果,未提交事务;
期间,事务B向表中插入了一条 id = 3 的记录,并提交事务;
事务A再次查询表中满足 id >= 1 且 id <= 6 的记录,却得到 5 条结果(mysql 5.7版本以后加上了next-key Lock----行锁+间隙锁);