数据库事务级别
1. 地球人都知道的,但往往你就不能说出口,所以事务的相关概念还是有必要提一下
事务特性(ACID特性)
- 原子性(Atomicity),事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做。
- 一致性(Consistency),事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
- 隔离性(Isolation),一个事务的执行不能被其他事务干扰。
- 持续性/永久性(Durability),一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。
事务隔离级别
由弱到强分别是:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ和SERIALIZABLE
ps:MySQL的默认事务隔离级别是REPEATABLE_READ,ORACLE、SQL Server、DB2和PostgreSQL的默认事务隔离级别是READ_COMMITED。
2. 事务到底是做什么的呢?下表是这四种事务隔离级别对脏读、不可重复读和幻读的支持情况:
隔离级别 | 丢失更新 |
脏读 (Dirty read) |
不可重复读 (Non-repeatable read) |
覆盖更新 |
幻读 (Phantom read) |
READ_UNCOMMITED | 允许 | 允许 | 允许 | 允许 | 允许 |
READ_COMMITED | 不允许 | 不允许 | 允许 | 允许 | 允许 |
REPEATABLE_READ | 不允许 | 不允许 | 不允许 | 不允许 | 允许 |
SERIALIZBLE | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |
数据库并发问题可以归结为下面几类:
- 丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖(A和B事务并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了)
- 脏读:一个事务允许读取其他正在运行的事务还没有提交的改变。这种情况的发生主要因为没有加锁。
- 不可重复读:不可重复读是指事务A读取了事务B已经提交的更改数据。不可重复读指的是一个事务内连续读却得到不同的结果,主要因为同时有其他事务更新了我们正在读取的数据。要达到允许可重复读的目的,我们必须让当前事务保持一个读共享锁。
- 覆盖更新:这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据(即A事务更新数据,然后B事务更新该数据,A事务查询发现自己更新的数据变了)
- 幻读:幻读指的是事务不是串行发生时发生的一种现象,是事务A读取了事务B已提交的新增数据。例如第一个事务对一个表的所有数据进行修改,同时第二个事务向表中插入一条新数据。那么操作第一个事务的用户就发现表中还有没有修改的数据行,就像发生了幻觉一样。解决幻读的方法是增加范围锁(range lock)或者表锁。
3.这几种事务级别到底是怎么工作的呢?
1)SERIALIZABLE:
添加范围锁(比如表锁,页锁等),直到transaction A结束。以此阻止其它transaction B对此范围内的insert,update等操作。
幻读,脏读,不可重复读等问题都不会发生。
2)REPEATABLE READ(可重复读)
对于读出的记录,添加共享锁直到transaction A结束。其它transaction B对这个记录的试图修改会一直等待直到transaction A结束。
可能发生的问题:当执行一个范围查询时,可能会发生幻读。
3)READ COMMITTED(提交读)
在transaction A中读取数据时对记录添加共享锁,但读取结束立即释放。其它transaction B对这个记录的试图修改会一直等待直到A中的读取过程结束,而不需要整个transaction A的结束。所以,在transaction A的不同阶段对同一记录的读取结果可能是不同的。
可能发生的问题:不可重复读。
4)READ UNCOMMITTED(未提交读)
不添加共享锁。在transaction A中可以读取到transaction B(未提交)中修改的数据。比如transaction B对R记录修改了,但未提交。此时,在transaction A中读取R记录,读出的是被B修改过的数据。
可能发生的问题:脏读。
参考文章:
1. 事务与数据库恢复原理
2. SQL语句执行过程详解