数据库隔离级别
文章目录
数据库隔离级别
隔离级别决定了事务的完整性对其他用户和系统的可见性。较低的隔离级别增加了许多用户在同一时间访问相同数据的能力,但也增加了用户可能遇到的并发效应(如脏读或丢失更新)的风险。
以下是四个常见的数据库隔离级别:
Serializable(可串行化)
:这是最高的隔离级别。并发事务被保证按顺序执行。Repeatable Read(可重复读)
:事务开始后,读取的数据保持不变。Read Committed(已提交读)
:只有在事务提交后,才能读取数据的修改。Read Uncommitted(未提交读)
:在事务提交之前,其他事务可以读取数据的修改。
在数据库中,脏读、不可重复读和幻读是常见的一致性问题。以下是它们的定义:
脏读(Dirty Read)
:脏读发生在一个事务读取了另一个未提交事务的数据。如果该未提交的事务失败,并回滚更改,那么第一个事务就会读取到无效的数据。不可重复读(Non-repeatable Read)
:不可重复读发生在一个事务的生命周期里多次读取同一数据行,但由于其他事务的提交,导致每次读取的数据都不同。幻读(Phantom Read)
:幻读发生在一个事务在读取满足某个条件的所有行时,另一个事务插入了新的满足该条件的行,导致第一个事务在再次读取时看到了“幻影”(即与上一次读取不一样的结果)行。
MYSQL默认隔离级别
可重复读
是MySQL的默认隔离级别由多版本一致性控制(MVCC)
和锁来保证。
下面流程描述了MVCC的实现过程:
- MVCC为每行数据添加了隐藏列:
transaction_id
和roll_pointer
。 - 当事务A开始时,会创建一个新的
Read View
,其transaction_id
为201。 - 随后,事务B开始,创建了一个新的
Read View
,其transaction_id
为202。 - 现在,事务A将余额修改为200,创建了一行新的日志,并且
roll_pointer
指向旧行。 - 在事务A提交之前,事务B读取了余额数据。事务B发现事务ID 201尚未提交,因此它读取了下一个已提交的记录(
transaction_id=200
)。即使事务A提交,事务B仍然根据事务B开始时创建的Read View
读取数据。因此,事务B始终读取的数据是余额为100的数据¹。
因此,基于上述实现,可以得出的是:
- MVCC主要通过允许多个事务读取(但不写入)同一行数据而不阻塞彼此,来提高读取性能,因为每个事务在事务开始时看到的是数据的快照。这通常被称为"非阻塞读取"。
- 然而,当涉及到写入数据时,情况就有些微妙了。MVCC确实允许并发写入,但只有在事务更新不同的行时才允许。如果多个事务试图更新同一行,那么它们将不得不等待彼此,类似于串行化隔离级别。这是为了维护数据一致性和防止冲突。
- 所以,虽然MVCC确实增加了读操作的并发性和性能,但它也允许一定程度的并发写操作,只要这些操作不更新同一行。
事实上,在使用MVCC的系统中,如果一个事务更新了一行数据,然后另一个事务试图更新同一行数据,那么具体的结果取决于MVCC的具体实现和冲突解决策略。
乐观并发控制(Optimistic Concurrency Control)
:
- 在 OCC 中,允许第二个事务继续进行并根据旧版本更新数据。
- 当第二个事务尝试提交其更改时,系统会检查冲突。如果检测到冲突(即第一个事务已提交其更改),则第二个事务将被中止并被迫重新启动。
- 这种方法允许更高的并发性,因为事务可以继续进行而不必等待锁,但这增加了冲突和中止的风险。
悲观并发控制(Pessimistic Concurrency Control)
:
- 在 PCC 中,第二个事务被阻止启动其更新,直到第一个事务提交或回滚。这确保了第二个事务始终看到数据的最新版本。
- 这种方法有效地防止了冲突,但它会导致较低的并发性,因为事务在继续进行之前必须等待锁。
问题MySQL的可重复读隔离级别能解决幻读吗?
MySQL 的可重复读(Repeatable Read)隔离级别可以解决幻读问题,但这主要是因为 MySQL 在这个隔离级别下使用了一种称为“Next-Key Locking”的锁定策略。
在标准的 SQL 规范中,可重复读隔离级别并不能保证解决幻读问题。幻读是指在一个事务内读取到了另一个并发事务插入的新行。标准的可重复读隔离级别只能保证在一个事务内多次读取同一行数据时,其值保持不变。
然而,MySQL 的 InnoDB 存储引擎在可重复读隔离级别下使用了 Next-Key Locking,这种锁定策略不仅锁定了查询涉及到的行,还锁定了这些行之间的“间隙”,防止其他事务在这些间隙中插入新行,从而有效地解决了幻读问题。
需要注意的是,这种行为是 MySQL 特有的,不是所有的数据库系统在可重复读隔离级别下都能解决幻读问题。在一些其他的数据库系统中,只有最高的隔离级别——串行化(Serializable)才能解决幻读问题。
文章作者 bobo
上次更新 2023-12-13