什么是脏读?

Buy owner data from various industry. Like home owner, car owner, business owner etc type owner contact details
Post Reply
suhashini25
Posts: 76
Joined: Tue Dec 03, 2024 5:03 am

什么是脏读?

Post by suhashini25 »

在数据库并发控制中,脏读(Dirty Read)是一种常见的隔离性问题,它发生在一个事务读取了另一个并发事务尚未提交(uncommitted)的数据时。如果那个尚未提交的事务最终被回滚(Rollback),那么第一个事务读取到的数据就是“脏数据”——因为它从未在数据库中真正存在过或被确认为有效数据。

1. 脏读的产生过程
让我们通过一个银行转账的例子来理解脏读:

假设有一个账户 A,初始余额为 1000 元。

事务 T1 开始:

T1 从账户 A 扣除 200 元。
此时,账户 A 的余额变为 800 元(这笔修改还在 T1 的内存中,尚未提交到数据库)。
事务 T2 开始:

T2 查询账户 A 的余额。
脏读发生! T2 读取到了 T1 尚未提交的 800 元。
事务 T1 遇到问题并回滚:

T1 因为某种原因(例如,系统错误、业务逻辑判断失败)决定回滚。
账户 A 的余额被恢复到 T1 开始前的状态,即 1000 元。
事务 T2 继续其操作:

T2 基于它读取到的“800 元”数据进行后续的计算或决策。
问题: 事务 T2 读取到的 800 元数据是无效的,因为它从未真正提交到数据库。T2 进行了基于错误数据的操作,这可能导致最终的数据不一致或错误的业务决策。

2. 脏读的危害
脏读是最低的事务隔离级别(即“读未提交”隔离级别)下可能出现的问题,它的危害主要体现在以下几个方面:

数据不一致性: 这是最直接的危害。如果基于脏数据进行了后续操作,最终提交的数据可能与实际不符,破坏了数据库的完整性。
错误的业务决策: 应用程序可能根据脏数据做出 美国赌博数据 错误的判断或生成错误的报告。例如,一个库存系统可能根据一个正在进行的、但最终会被取消的订单所扣除的库存量来判断是否还有库存,导致错误的销售决策。
难以调试: 由于数据的不确定性,排查问题会变得非常困难。你看到的数据可能只是昙那花一现,很快就消失了。
3. 如何避免脏读?
要避免脏读,需要提高数据库的事务隔离级别。SQL 标准定义了四个隔离级别,从低到高依次是:

读未提交(Read Uncommitted):

允许脏读。这是最低的隔离级别,事务可以读取到其他事务未提交的修改。
虽然并发性最高,但数据一致性最差,在生产环境中极少使用。
读已提交(Read Committed):

这是大多数数据库(如 SQL Server、Oracle、PostgreSQL)的默认隔离级别。
避免了脏读。 一个事务只能读取到其他事务已经提交的修改。当一个事务修改数据时,它会给数据加上排他锁(X 锁),直到事务提交或回滚,其他事务无法读取这部分数据。
解决了脏读问题,但可能仍然面临**不可重复读(Non-repeatable Read)和幻读(Phantom Read)**的问题。
可重复读(Repeatable Read):

MySQL 的默认隔离级别。
避免了脏读和不可重复读。 在一个事务中,对同一数据的多次读取会得到相同的结果,即使有其他事务提交了修改。通常通过对读取的数据加共享锁(S 锁)来阻止其他事务对数据的修改,或者通过 MVCC(多版本并发控制)来读取旧版本的数据。
仍然可能面临幻读的问题(在某些实现中,如 MySQL 的 InnoDB 引擎,在特定条件下也能避免幻读)。
串行化(Serializable):

最高的隔离级别。
避免了脏读、不可重复读和幻读。 事务之间完全隔离,就好像它们是串行执行的一样。
虽然数据一致性最好,但并发性最低,因为需要大量的锁,可能会导致性能瓶颈。在生产环境中通常只在对数据一致性要求极高且并发冲突不频繁的场景下使用。
总结:

避免脏读最直接有效的方法是将事务隔离级别设置为读已提交(Read Committed)或更高。虽然提高隔离级别会牺牲一定的并发性,但它能确保数据在复杂并发环境下的正确性和可靠性,这在大多数业务应用中都是至关重要的。
Post Reply