暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

RDBMS事务隔离级别

Wei.Bu 2024-04-30
372

"脏读"(Dirty Read)是数据库并发控制中的一个概念,特别是在涉及事务(Transaction)的上下文中。当多个事务并发访问数据库时,可能会出现数据不一致的问题,而脏读就是其中一种情况。

脏读描述了一个事务读取了另一个尚未提交的事务的修改。具体来说,当一个事务A正在修改数据,而另一个事务B在这个修改提交之前读取了这个数据,那么事务B读取到的就是“脏”数据,因为这个数据可能随后会被事务A回滚(Rollback),导致事务B读取到的数据并不是最终的数据。

"不可重复读"(Non-repeatable Read)是数据库事务并发控制中的一个问题,它发生在同一事务中多次读取同一数据项时,由于其他并发事务的修改或删除操作,导致每次读取的结果可能不同

具体来说,当事务A在读取某个数据项后,事务B修改或删除了该数据项并提交,然后事务A再次读取该数据项时,发现数据已经发生了变化。这种情况下,事务A的两次读取结果是不一致的,因此称为"不可重复读"。

不可重复读违反了事务的隔离性要求,因为它允许一个事务读取到另一个事务的未提交修改。这可能导致数据的不一致性和应用程序的逻辑错误。

"幻读"(Phantom Read)是数据库事务并发执行时的一种现象,发生在某个事务读取了某个范围内的记录后,另一个并发事务插入或删除了这个范围内的记录,当该事务再次读取同样的范围时,看到了之前不存在的“幻影”记录或某些记录突然消失了

具体来说,幻读涉及以下情况:

  • 插入幻读:一个事务读取了某些行的集合,然后另一个并发事务插入了一些新的行到集合中。当第一个事务再次读取同样的范围时,它会看到这些新插入的“幻影”行。
  • 删除幻读:类似地,一个事务读取了某些行的集合,然后另一个并发事务删除了集合中的一些行。当第一个事务再次读取时,它发现之前读取的一些行不见了。

在SQL标准中,有四种事务隔离级别,其中:

  • 读未提交(Read Uncommitted):允许脏读、不可重复读和幻读。
  • 读已提交(Read Committed):不允许脏读,但可能出现不可重复读和幻读。这是大多数数据库系统的默认隔离级别,包括Oracle。Oracle数据库默认使用读已提交隔离级别,这意味着它允许幻读的发生。如果你需要避免幻读,可以考虑使用更严格的隔离级别,如可重复读或串行化。但请注意,使用更严格的隔离级别可能会对并发性能产生负面影响。因此,在选择隔离级别时,需要权衡数据一致性和性能之间的需求。
  • 可重复读(Repeatable Read):不允许脏读和不可重复读,但可能出现幻读。MySQL的InnoDB存储引擎在默认设置下使用这种隔离级别,并通过多版本并发控制(MVCC)实现。
  • 串行化(Serializable):最严格的隔离级别,它通过强制事务串行执行来避免脏读、不可重复读和幻读。

描述下举例中幻读不同会话,不同范围的修改顺序。并详细描述下。

幻读涉及到的是两个或多个并发执行的事务,它们在不同的时间点对同一数据集进行读取或修改操作,从而导致一个事务在两次读取之间看到的数据发生了变化。下面是一个具体的例子,用来描述幻读中不同会话和不同范围的修改顺序。

假设我们有两个数据库会话(Session A和Session B),它们都在对同一个数据库表进行操作。这个表可能是一个商品表,包含商品的ID、名称和价格等信息。

1. Session A开始一个事务,并读取商品表中的数据

  • Session A执行一个SELECT查询,比如SELECT * FROM products WHERE price > 100,用于获取价格高于100的所有商品。假设此时查询结果返回了10条记录。

2. 在Session A提交事务之前,Session B开始另一个事务,并插入新的商品记录

  • Session B插入了一个新的商品记录,其价格高于100。这个插入操作是在Session A的第一次读取之后发生的。

3. Session A再次执行相同的SELECT查询

  • 由于Session B已经插入了一个新的符合条件的商品记录,Session A的第二次查询将返回11条记录(包括原来的10条和新插入的1条)。

幻读发生

  • 在这个例子中,Session A在同一个事务中两次执行了相同的查询,但由于Session B的插入操作,两次查询返回的结果集不一致。Session A在第二次查询时“看到”了之前不存在的商品记录,就像出现了“幻影”一样。这就是幻读现象。

幻读对于某些应用来说可能是个问题,特别是那些依赖于数据集合稳定性或可预测性的应用。为了解决这个问题,数据库管理系统提供了不同的事务隔离级别。在较高的隔离级别(如可重复读或串行化)下,数据库会采取额外的措施来避免幻读的发生,但这通常会以牺牲并发性能为代价。因此,在选择适当的事务隔离级别时,需要根据应用的具体需求和性能考虑进行权衡。

幻读,不可重复读区别

幻读(Phantom Read)和不可重复读(Non-repeatable Read)在数据库事务并发控制中是两个不同的概念,主要区别在于它们所描述的数据不一致性的场景不同。

  1. 不可重复读:

不可重复读主要关注的是在一个事务内,对于同一份数据的读取结果不一致。具体来说,当事务A在读取某个数据项后,事务B修改了该数据项并提交,然后事务A再次读取该数据项时,发现数据已经发生了变化。这种情况下,事务A的两次读取结果是不一致的,因此称为“不可重复读”。

不可重复读违反了事务的隔离性要求,因为它允许一个事务读取到另一个事务的已提交修改。这可能导致数据的不一致性和应用程序的逻辑错误。

  1. 幻读:

幻读主要关注的是在一个事务内,对于同一数据范围的多次查询结果不一致。具体来说,当事务A在查询某个数据范围后,事务B在该范围内插入了新的数据并提交,然后事务A再次查询该范围时,发现出现了新的数据行。这种情况下,事务A的两次查询结果是不一致的,就像产生了幻觉一样,因此称为“幻读”。

幻读也违反了事务的隔离性要求,因为它允许一个事务读取到另一个事务的已提交新增数据。这可能导致数据的不一致性和应用程序的逻辑错误。

总结来说,不可重复读和幻读都是由于并发事务修改数据而导致的数据不一致性问题。不可重复读关注的是单个数据项在事务内的读取结果不一致,而幻读关注的是数据范围在事务内的查询结果不一致。

事务隔离级别是数据库管理系统(DBMS)中用于定义事务之间如何相互隔离的机制,从而确保数据的一致性和完整性。这些隔离级别决定了事务在并发执行时能够访问和修改数据的程度,以及数据对其他并发事务的可见性。

以下是四种常见的事务隔离级别及其详细解释:

  1. 读未提交(Read Uncommitted)
    • 定义:一个事务可以读取另一个尚未提交的事务的修改。
    • 问题:这种隔离级别允许脏读(Dirty Read),即一个事务可以读取到另一个事务尚未提交的数据,这些数据可能会因为被回滚而失效。此外,还可能出现不可重复读(Non-repeatable Read)和幻读(Phantom Read)问题。
    • 适用场景:该隔离级别主要适用于那些对数据一致性要求不高,但需要极高并发性能的场景。
  2. 读已提交(Read Committed)
    • 定义:一个事务只能读取另一个已经提交的事务的修改。
    • 问题:这种隔离级别解决了脏读问题,因为它保证读取到的数据是已经提交的。但是,它仍然可能出现不可重复读和幻读问题。不可重复读是指在一个事务内,多次读取同一数据可能会得到不同的结果(因为其他事务可能在两次读取之间修改了数据)。幻读是指在一个事务内,对同一范围的查询可能会返回不同的结果集(因为其他事务可能在这个范围内插入了新的数据)。
    • 适用场景:该隔离级别适用于大多数应用场景,因为它提供了相对较高的数据一致性和并发性能。
  3. 可重复读(Repeatable Read)
    • 定义:对同一字段的多次读取结果都是一致的。这通常是通过多版本并发控制(MVCC)来实现的,即每个事务都会看到一个一致的数据快照。
    • 问题:这种隔离级别解决了脏读和不可重复读问题,但是仍然可能出现幻读。
    • 适用场景:该隔离级别适用于那些需要确保在事务执行期间读取到的数据保持一致性的场景,如金融交易等。
    • 使用共享锁(Shared Lock)或多版本并发控制(MVCC)等技术来实现。
  4. 串行化(Serializable)
    • 定义:最高的隔离级别。它通过对事务进行排序,使得它们逐个执行,从而完全遵守ACID属性中的隔离性要求。
    • 问题:这种隔离级别可以完全避免脏读、不可重复读和幻读问题,但因为它强制事务串行执行,所以并发性能最低。
    • 适用场景:该隔离级别适用于那些对数据一致性要求极高,可以接受较低并发性能的场景。

在选择事务隔离级别时,需要根据应用的具体需求进行权衡。更高的隔离级别可以提供更好的数据一致性和可靠性,但可能会降低并发性能;而较低的隔离级别则可以提高并发性能,但可能会增加数据不一致性的风险。因此,需要根据实际情况来选择合适的事务隔离级别。

Oracle数据库默认的事务隔离级别是读已提交(Read Committed)。这种隔离级别保证了当某个事务访问数据时,它只能看到已经提交的事务所做的改变。也就是说,一个事务从开始到结束,看到的是在此期间已经提交的其它事务的更改,但无法看到未提交的更改。这避免了脏读(Dirty Read)问题,即一个事务读取到另一个事务尚未提交的数据,但这些数据可能会因为被回滚而失效。

如果需要更高的隔离级别来避免这些问题,可以考虑使用Oracle的串行化(Serializable)隔离级别。但请注意,这可能会降低并发性能,因为事务需要按顺序执行。

Oracle数据库串行化科普介绍

1. 简要介绍Oracle数据库的串行化概念

在Oracle数据库中,串行化(Serialization)是一种事务隔离级别,它确保了事务之间按照某种顺序逐个执行,从而避免了数据的不一致性和并发问题。在串行化隔离级别下,数据库管理系统会强制事务串行执行,即一个事务必须等待另一个事务完成后才能开始执行。这样,每个事务在其执行过程中都能够看到一个一致的数据视图,从而保证了数据的一致性和完整性。

2. 阐述串行化在数据库中的作用和优势

  • 保证数据一致性:串行化能够阻止不可重复读取(nonrepeatable read)或幻读(phantom read)的现象,确保事务读取到的数据在事务执行期间保持一致。
  • 避免并发冲突:通过强制事务串行执行,串行化避免了多个事务同时修改同一数据导致的冲突和错误。
  • 简化事务管理:在串行化隔离级别下,事务之间的依赖关系变得简单明了,从而简化了事务管理和调试工作。

3. 列举几个Oracle数据库串行化的实际应用场景

  • 金融交易系统:在金融交易系统中,数据的准确性和一致性至关重要。通过串行化隔离级别,可以确保每笔交易在执行过程中不会受到其他事务的干扰,从而保证了交易的安全性和准确性。
  • 在线预订系统:在在线预订系统中,多个用户可能同时尝试预订同一资源。通过串行化隔离级别,可以确保每个预订请求按照顺序逐个处理,从而避免了资源超订或预订冲突的问题。
  • 数据备份和恢复:在数据库备份和恢复过程中,需要确保备份数据的一致性和完整性。通过串行化隔离级别,可以确保在备份过程中不会受到其他事务的干扰,从而保证了备份数据的质量。

4. 强调串行化对于提高数据库性能和效率的重要性

虽然串行化可能会降低并发性能,但在某些情况下,它可以通过减少数据冲突和错误来提高数据库的整体性能和效率。例如,在金融交易系统中,虽然串行化可能导致事务处理速度变慢,但它可以确保每笔交易的正确性和安全性,从而减少了因数据不一致而导致的错误和损失。

5. 给出一些建议或最佳实践,以帮助用户更好地实施Oracle数据库串行化

  • 根据业务需求选择合适的隔离级别:在实施串行化之前,需要仔细分析业务需求和数据访问模式,选择最适合的隔离级别。对于需要高并发性能的场景,可以考虑使用读已提交(Read Committed)或更低的隔离级别;而对于需要严格保证数据一致性的场景,则可以使用串行化隔离级别。
  • 优化事务设计和处理逻辑:为了减少事务之间的冲突和等待时间,可以优化事务的设计和处理逻辑。例如,将大事务拆分成多个小事务、减少不必要的锁操作和降低事务的持续时间等。
  • 监控和调整数据库性能:在实施串行化后,需要定期监控数据库的性能和响应时间,并根据实际情况进行调整和优化。例如,可以通过调整数据库的缓存大小、增加并发连接数或优化索引等方式来提高数据库的性能和效率。
  • 备份和恢复策略:在实施串行化之前,需要制定完善的备份和恢复策略,以确保在发生数据丢失或损坏时能够及时恢复数据。同时,也需要定期测试备份和恢复流程的有效性。

在Oracle数据库中,更改事务的隔离级别到串行化(Serializable)通常涉及在事务的声明或设置中进行指定。但请注意,Oracle并没有直接提供一个简单的SQL命令来全局更改默认的隔离级别。然而,你可以通过在事务中使用特定的锁定机制或设置来实现串行化的效果。

以下是一些建议和方法来实现Oracle中的串行化:

  1. 使用SET TRANSACTION命令(注意:Oracle可能不支持直接使用SET TRANSACTION来设置隔离级别,但某些数据库系统支持):
    尽管Oracle可能不直接支持使用SET TRANSACTION来设置隔离级别为SERIALIZABLE,但在某些数据库系统中,你可以使用类似以下的命令:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

但在Oracle中,你可能需要采取其他方法。

  1. 使用SELECT ... FOR UPDATE语句
    通过在查询中使用FOR UPDATE子句,你可以锁定所选的行或表,从而阻止其他事务修改或锁定这些行,直到当前事务完成。这可以模拟串行化的效果,因为它确保了在同一时间只有一个事务可以修改特定的数据。

SELECT * FROM your_table WHERE your_condition FOR UPDATE;

  1. 使用表级锁
    Oracle支持表级锁,你可以使用LOCK TABLE语句来锁定整个表。这将阻止其他事务访问或修改表中的数据,直到锁被释放。但请注意,表级锁可能会对并发性能产生显著影响。

LOCK TABLE your_table IN EXCLUSIVE MODE;

  1. 使用DBMS_LOCK包
    Oracle提供了一个名为DBMS_LOCK的包,它允许你创建和管理数据库锁。你可以使用此包来创建应用程序特定的锁,并在需要时获取和释放它们。这为你提供了更大的灵活性来控制并发访问和数据一致性。
  2. 考虑使用应用程序逻辑
    在某些情况下,你可能需要在应用程序逻辑中实施串行化,而不是在数据库级别。例如,你可以使用队列、消息传递系统或分布式锁来确保在应用程序的不同部分之间按顺序处理任务。
  3. 评估和调整并发控制参数
    Oracle提供了许多参数和配置选项来优化并发控制和事务管理。你可以评估和调整这些参数以改善性能和数据一致性,同时实现串行化的效果。这可能需要深入了解Oracle的并发控制机制和性能调优技术。

请注意,在更改事务的隔离级别或实施串行化之前,你应该仔细评估其对数据库性能和并发能力的影响。串行化通常会降低并发性能,因为它限制了多个事务同时访问和修改数据的能力。因此,在选择适当的并发控制策略时,你需要权衡数据一致性和并发性能之间的需求。

MySQL 支持四种事务隔离级别,这些级别决定了事务如何与其他事务进行交互以及它们如何看到数据。以下是对这四种隔离级别的描述:

  1. 读未提交(Read Uncommitted)
    • 这是最低的隔离级别。在这个级别,一个事务可以读取到另一个尚未提交的事务的修改。这可能导致“脏读”,即读取到其他事务尚未提交的、可能会被回滚的数据。此外,还可能出现“不可重复读”和“幻读”问题。
  2. 读已提交(Read Committed)
    • 这是大多数数据库系统的默认隔离级别(但不是 MySQL 的默认级别)。在这个级别,一个事务只能读取到其他已经提交的事务的修改。这解决了“脏读”问题,但由于其他事务的修改,可能会出现“不可重复读”和“幻读”问题。
  3. 可重复读(Repeatable Read)
    • 这是 MySQL 的默认隔离级别(在 InnoDB 存储引擎中)。在这个级别,一个事务在其整个生命周期中都会看到一致的数据快照。这意味着在事务开始时读取的数据在事务的后续读取中仍然是一致的,即使其他事务在此期间修改了数据。但是,如果在事务中多次读取同一范围的数据,而其他事务在此期间插入了新的数据,那么可能会出现“幻读”问题。
  4. 串行化(Serializable)
    • 这是最高的隔离级别。在这个级别,所有的事务依次逐个执行,这样事务之间就不可能产生干扰。这解决了“脏读”、“不可重复读”和“幻读”问题,但可能显著降低并发性能,因为事务需要等待其他事务完成才能开始。

你可以使用以下 SQL 语句来查询和设置 MySQL 的事务隔离级别:

查询当前隔离级别:

SELECT @@transaction_isolation;

设置隔离级别(例如,设置为可重复读):

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

请注意,更改隔离级别可能会对数据库的性能和并发能力产生显著影响,因此在更改之前应该仔细评估你的需求。

TiDB、OceanBase、OpenGauss 和 达梦(DM)数据库默认的事务隔离级别各不相同,以下是它们的默认隔离级别:

  1. TiDB
    • 默认隔离级别是 读已提交(Read Committed)。但在某些版本中,它可能支持其他的隔离级别,如可重复读(Repeatable Read)。
  2. OceanBase
    • 在 MySQL 模式下,默认隔离级别是 读已提交(Read Committed)
    • OceanBase 实际实现了两种隔离级别:读已提交和可串行化。当用户指定可重复读的隔离级别时,OceanBase 实际上使用的是可串行化。
  3. OpenGauss
    • 在 OpenGauss 5.0.0 之前的版本中,默认隔离级别是 读已提交(Read Committed)
    • OpenGauss 5.0.0 支持读已提交(Read Committed)和可重复读(Repeatable Read)两种事务隔离级别,但默认仍然是读已提交。
    • 请注意,OpenGauss 目前功能上不支持 SERIALIZABLE 隔离级别,但可重复读(Repeatable Read)在 OpenGauss 中可能提供了类似 SERIALIZABLE 的某些特性。
  4. 达梦(DM)数据库
    • 默认隔离级别是 读提交(Read Committed)。达梦数据库支持三种事务隔离级别:读未提交、读提交和串行化,但读提交是默认使用的事务隔离级别。

这些默认隔离级别是为了在满足数据一致性的同时,尽可能地提高数据库的并发性能。然而,根据具体的应用场景和需求,你可能需要调整这些隔离级别以达到最佳的性能和一致性。在调整之前,请确保你了解各种隔离级别的特点和影响。

MySQL的默认隔离级别是REPEATABLE READ(可重复读)。在这个级别下,对同一字段的多次读取结果都是一致的。这是因为在这个级别下,事务会创建一个一致性视图,即事务开始时数据库中的某个时间点的快照。这意味着事务在执行期间看到的数据与其他事务并发修改的数据是不一样的,即使其他事务修改了某个数据,事务在自己的一致性视图中看到的仍然是事务开始时的快照。

REPEATABLE READ级别下,事务可以保证以下几点:

  1. 读取的数据与事务开始时一致,在事务执行期间不会发生变化。
  2. 事务期间其他并行事务所做的更改对该事务是不可见的,不会影响该事务读取的数据。

但是,REPEATABLE READ并不能完全避免幻读(Phantom Read)现象,即在事务执行过程中,其他事务插入新的记录,导致当前事务在后续查询中看到了之前不存在的记录。不过,InnoDB存储引擎通过多版本并发控制(MVCC)和Next-Key Locking机制解决了这个问题。

除了REPEATABLE READ之外,MySQL还支持其他三种事务隔离级别:READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)和SERIALIZABLE(可串行化)。这些隔离级别提供了不同程度的数据一致性和并发性能之间的权衡。

MySQL 如何做到可重复读,特别是 InnoDB 存储引擎,主要依赖于**多版本并发控制(MVCC)**技术。MVCC 允许数据库在读取数据的同时,其他事务也可以并发地对其进行修改,从而提高了并发性能。

以下是 MVCC 在 InnoDB 中实现可重复读的基本原理:

  1. 快照读:当事务进行 SELECT 操作时,InnoDB 会为该事务创建一个数据快照(Snapshot),这个快照是基于事务开始时的数据库状态。事务在后续的读取操作中,都会基于这个快照来读取数据,从而保证了事务内多次读取结果的一致性。
  2. 版本链:InnoDB 中的每一行数据都会有一个版本链,记录了该行数据的所有版本。当事务对数据进行修改时,并不会直接修改原始数据,而是会在版本链中新增一个版本,包含修改后的数据以及相关的元数据(如事务ID、回滚指针等)。
  3. Read View:为了确定事务应该读取哪个版本的数据,InnoDB 引入了 Read View 的概念。Read View 可以理解为事务在某一时刻对数据的一个一致性视图。它包含了当前活跃的事务列表以及一个“低水位线”(Low Watermark)和一个“高水位线”(Up Watermark)。只有在这个范围内的数据版本,才会被事务读取。
  4. 非锁定读:由于 MVCC 的存在,InnoDB 的读操作(SELECT)都是非锁定的,即读操作不会阻止其他事务对数据进行修改。这大大提高了并发性能。

相比于其他数据库,如 PostgreSQL,虽然也支持 MVCC,但具体的实现细节和语义可能会有所不同。例如,PostgreSQL 的默认隔离级别是 READ COMMITTED,而 MySQL 的默认隔离级别是 REPEATABLE READ。此外,两者在 MVCC 的实现上也可能存在一些差异,如版本链的管理、Read View 的生成等。

需要注意的是,虽然 MVCC 提高了并发性能,但也可能带来一些额外的开销,如存储空间的占用(因为需要保存多个数据版本)以及内存的开销(因为需要维护版本链和 Read View 等数据结构)。因此,在设计和使用数据库时,需要根据具体的应用场景和需求来权衡并发性能和资源开销之间的关系。

ACID 是数据库管理系统(DBMS)中事务(Transaction)的四个基本属性的简称,用于确保事务的可靠执行。ACID 分别是:

  1. 原子性(Atomicity)
    • 事务是一个原子操作单元,其对数据的修改要么全都执行,要么全都不执行。事务的原子性确保动作要么完全发生,要么完全不发生。如果事务中的某个步骤失败,则整个事务都会失败,所有由该事务所做的更改都会被撤消。
  2. 一致性(Consistency)
    • 事务必须使数据库从一个一致性状态变换到另一个一致性状态。一致性的含义是:数据不会因为事务的执行而破坏数据库的完整性约束,数据不会被破坏。在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
  3. 隔离性(Isolation)
    • 在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的隔离空间,一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。事务隔离级别定义了一个事务中的数据在何时对另一个事务变得可见。
  4. 持久性(Durability)
    • 一旦事务完成,无论系统发生什么故障,其结果都是永久的。即,一旦事务提交,则其结果就是永久性的。即使发生系统崩溃,重新启动数据库系统后,数据库也能恢复到事务成功结束时的状态。

这四个属性共同保证了数据库事务的可靠执行。在数据库管理系统中,事务是恢复和并发控制的基本单位。通过确保事务的ACID属性,数据库系统可以维护数据的一致性和完整性,同时支持多个用户并发访问和修改数据。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论