事务概述
事务指的是逻辑上的一组操作,组成这组操作的各个单元要么全都成功,要么全都失败。
事务作用:保证在一个事务中多次SQL操作要么全都成功,要么全都失败。
事务基本特性
(ACID,是针对单个事务的一个完美状态)
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。保证一致性的工具:锁。
隔离性(Isolation)
事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。隔离性由隔离级别保障!
正常情况下数据库是做不到完完全全的隔离,可以增强隔离级别,但是效率会非常低。
read uncommitted --> read committed --> repeatable read --> serializable 【MySQL默
认隔离级别RR】
事务并发问题:脏读、不可重复读,幻读
丢失更新的问题!
MVCC:multiple version concurrency control(多版本并发控制)为什么需要MVCC?
能不能在隔离性和效果之间找一个平衡点呢?
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
能不能做到100%?
事务并发问题【事务隔离不足导致】
如果不考虑隔离性,事务存在3中并发访问问题。
1. 脏读:一个事务读到了另一个事务未提交的数据
2. 不可重复读:一个事务读到了另一个事务已经提交(update)的数据。引发另一个事务,在事务中的多次查询结果不一致。
3. 虚读 /幻读:一个事务读到了另一个事务已经插入(insert)的数据。导致另一个事务,在事务中多次查询的结果不一致。
事务隔离级别
数据库规范规定了4种隔离级别,分别用于描述两个事务并发的所有情况。
read uncommitted
读未提交,一个事务读到另一个事务没有提交的数据。
存在:3个问题(脏读、不可重复读、幻读)。
解决:0个问题
read committed
读已提交,一个事务读到另一个事务已经提交的数据。
存在:2个问题(不可重复读、幻读)。
解决:1个问题(脏读)
repeatable read
可重复读,在一个事务中读到的数据始终保持一致,无论另一个事务是否提交。
存在:1个问题(幻读)。
解决:2个问题(脏读、不可重复读)
serializable串行化
同时只能执行一个事务,相当于事务中的单线程。
存在:0个问题。
解决:3个问题(脏读、不可重复读、幻读)
安全和性能对比
安全性: serializable > repeatable read > read committed > read uncommitted
性能 : serializable < repeatable read < read committed < read uncommitted
常见数据库的默认隔离级别
MySql: repeatable read
Oracle: read committed
事务案例
设置数据库的隔离级别
set session transactionisolation level 级别字符串
级别字符串: read uncommitted 、 read committed 、 repeatable read 、serializable
例如: set session transaction isolation level read uncommitted;
读未提交:read uncommitted
时间 | 事务A | 事务B |
T0 | 设置A事务隔离级别【读未提交】 | 设置B事务隔离级别【读未提交】 |
T1 | 开始A事务 | 开始B事务 |
T2 | 查询 | |
T3 | 更新数据 | |
T4 | 再次查询:查询到B未提交数据【脏读】 | |
T5 | 回滚 | |
T6 | 再次查询:B未提交数据消失 | |
T7 | A事务提交【必须提交否则会对下次测产生影响】 | B事务提交 |
注意:完成之后必须结束事务,commit,
读已提交:read committed
时间 | 事务A | 事务B |
T0 | 设置A事务隔离级别【读已提交】 | 设置B事务隔离级别【读已提交】 |
T1 | 开始A事务 | 开始B事务 |
T2 | 查询 | |
T3 | 更新数据 | |
T4 | 再次查询:数据没变,解决脏读问题 | |
T5 | B事务提交 | |
T6 | 再次查询:数据改变,存在不可重复读问题 | |
T7 | A事务提交 |
可重复读:repeatable read
时间 | 事务A | 事务B |
T0 | 设置A事务隔离级别【可重复读】 | 设置B事务隔离级别【可重复读】 |
T1 | 开始A事务 | 开始B事务 |
T2 | 查询 | |
T3 | 更新数据 | |
T4 | 再次查询:数据没变,解决脏读问题 | |
T5 | B事务提交 | |
T6 | 再次查询:数据改变,存在不可重复读问题 | |
T7 | A事务提交 |
串行化:serializable
时间 | 事务A | 事务B |
T0 | 设置A事务隔离级别【串行化】 | 设置B事务隔离级别【串行化】 |
T1 | 开始A事务 | 开始B事务 |
T2 | 查询 | |
T3 | 更新数据--提示等待,如果A没有进一步操作B将等待超时 | |
T4 | A事务提交或者回滚 | |
T5 | B等待结束,执行操作 | |
T6 | B事务提交 |