PostgreSQL中的事务隔离级别

发布时间 2023-12-19 21:02:56作者: 旺仔真知棒

PostgreSQL中的事务隔离级别在确保多用户数据库环境中的数据一致性、完整性和并发控制方面起着至关重要的作用。当多个事务并发执行时,隔离级别定义了它们之间的相互隔离的程度。PostgreSQL提供了一系列的隔离级别,每个级别都有自己的一套保证和权衡,允许开发人员根据特定的需求定制应用程序的行为。

隔离级别规定事务如何观察其他事务所做的更改,以及它们如何保护数据不受并发修改的影响。它们可以防止常见的问题,如脏读(读取未提交的数据)、不可重复读(多次读取之间发生更改的数据)和幻读(看到其他事务插入的新行)。

隔离级别 脏读 不可重复读 幻读 序列化异常
读未提交 允许,但不在 PG 中 可能 可能 可能
读已提交 不可能 可能 可能 可能
可重复读 不可能 不可能 允许,但不在 PG 中 可能
可序列化 不可能 不可能 不可能 不可能

SQL 标准定义了四种隔离级别,但是postgreSQL只实现了三种不同的隔离级别,即 PostgreSQL 的读未提交模式的行为和读已提交相同。

  • 脏读

    当一个事务读取已被另一个事务修改的数据,但修改的事务尚未提交时。这可能导致不一致和不正确的结果。

    | AccountNumber | AccountHolder | Balance |
    |---------------|---------------|---------|
    | 1001          | Alice         | $100    |
    | 1002          | Bob           | $150    |
    

    事务1:

    1. 事务开始。
    2. 读取账号1001 (Alice的账户)的当前余额为100美元。

    事务2:

    1. 事务开始。
    2. 将账号1001的余额更新为200美元(增加Alice的余额)。

    回到事务1:

    1. 读取帐号1001的余额得到$200(脏读)。
    2. 根据读余额执行计算,并从中扣除50美元。

    事务2:

    1. 提交事务,账号1001的余额更新为200美元。

    在这个例子中,事务1 (T1)执行了一次脏读。它在事务2 (T2)提交其更改之前读取Alice的账户余额。结果,T1根据脏读数进行了计算,从不准确的200美元余额中扣除了50美元。一旦T2提交了它的更改,正确的余额变成了200美元,但是T1的计算已经基于不正确的脏读值。

  • 不可重复读

    当一个事务读取数据值时,另一个事务修改或更新该值并提交更改。当第一个事务试图再次读取相同的值时,它会遇到与最初读取的值不同的值。这种不一致可能导致意外行为和数据完整性问题。

    | StudentID | Name   | Age |
    |-----------|--------|-----|
    | 1         | Alice  | 20  |
    | 2         | Bob    | 22  |
    

    事务1:

    1. 事务开始
    2. 读取ID为1 (Alice)的学生的年龄为20。

    事务2:

    1. 事务开始。
    2. 将ID为1 (Alice)的学生的年龄更新为21岁。
    3. 提交事务。

    回到事务1:

    1. 再次读取ID为1 (Alice)的学生的年龄,并获得更新后的值21。

    这个例子中,不可重复读取现象发生在事务1 (T1)中。当T1初始读取Alice (ID为1的学生)的年龄时,得到的值为20。然而,当T1仍然处于活动状态时,事务2 (T2)将Alice的年龄修改为21岁并提交了更改。当T1再次读取Alice的年龄时,它遇到的是更新后的21,而不是原来的20。

  • 幻读

    当某个事务根据某个条件检索一组行,另一个事务插入、更新或删除符合该条件的行。此时,当第一个事务重新执行相同的查询时,它会观察到一组不同的行,就好像在两次执行之间“出现”或“消失”了新行一样。

    | ProductID | ProductName  | Price |
    |-----------|--------------|-------|
    | 1         | Laptop       | $800  |
    | 2         | Smartphone   | $400  |
    

    事务1:

    1. 事务开始。
    2. 执行一个查询来检索价格小于$500的所有产品。

    事务2:

    1. 事务开始。
    2. 插入一个新产品,ProductID为3,ProductName为“Tablet”,价格为350美元。
    3. 提交事务。

    回到事务1:

    1. 重新执行相同的查询来检索价格小于$500的产品。然而,这次它返回两行。

    在本例中,当事务1 (T1)在第二次执行同一查询时遇到一组不同的行时,就会出现幻读现象。这是因为事务2 (T2)在T1的两次执行之间插入了与T1的查询条件(“Tablet”,价格为350美元)匹配的新行。结果,T1得到一个不知道从哪里冒出来的记录。