代码之家  ›  专栏  ›  技术社区  ›  mljrg

PostgreSQL隔离级别的行为

  •  3
  • mljrg  · 技术社区  · 7 年前

    我正在阅读 PostgreSQL Manual 但文本的描述却发现不够清晰,缺乏实例。

    例如,以下两段不清楚谁在学习PostgreSQL:

    insert with an on conflict do update子句的行为类似。读入 提交模式下,建议插入的每一行都将插入或更新。 除非存在不相关的错误,否则这两种结果之一是有保证的。如果 冲突源于另一个事务,其效果尚不可见 对于insert,update子句将影响该行,即使可能 命令通常看不到该行的任何版本。”

    可重复读取模式为每个事务提供了严格的保证 查看数据库的完全稳定视图。然而,这个视图并不一定总是与同一级别并发事务的串行(一次一个)执行保持一致。例如,即使是此级别的只读事务,也可能看到更新的控制记录,以显示批处理已完成,但看不到逻辑上属于批处理一部分的详细记录之一,因为它读取了控制记录的早期版本。

    有人能举例说明这两段是什么吗?

    有人知道在哪里可以找到PostgreSQL隔离级别行为的正式描述吗?我之所以寻找它,是因为它是一个高级主题,我相信正式的描述将有助于阐明它是如何工作的,从而有助于避免事务之间的并发错误。

    更新 :另一个疑问是,当可序列化事务可以与其他隔离级别的其他事务同时运行时,如何处理数据库机器决定提交或中止它?数据库是否决定可序列化事务的结果,就像其他事务也是以可序列化隔离方式运行一样?

    谢谢

    更新2 :到目前为止,关于隔离级别的实现细节,我发现最好的方法是 PostgreSQL Wiki Serializable Page .

    2 回复  |  直到 7 年前
        1
  •  3
  •   Laurenz Albe    6 年前
    • READ COMMITTED :每个SQL语句都获取数据库的一个新快照,因此每个语句在提交并发事务时都会同时看到它们所做的更改。不能发生序列化错误。

    • REPEATABLE READ :事务中的第一条语句获取整个事务保留的数据库的快照,因此所有语句都看到数据库的相同状态。如果尝试修改在快照生成后由并发事务修改的行,则可能会发生序列化错误。这个隔离级别不比 读取已提交 .

    • SERIALIZABLE :任何可能导致结果与事务的某些串行执行顺序不一致的事务都将被中止,并出现序列化错误。可能有误报。这种隔离级别比其他级别更贵。

    具体问题解答:

    • INSERT ... ON CONFLICT 在读提交隔离中:

      如果事务1已插入行,但尚未提交,则事务2正在运行 插入…论冲突 将等待事务1提交或回滚,然后根据需要进行更新或插入。不能发生约束冲突。

    • 批处理作业和 可重复读取 :

      这一段很黑;忽略它。它试图说明两个并发的可重复读取翻译可以产生与任何串行执行不一致的结果。

      一个更好的例子可能是两个并发事务,它们都读取相同的数据并根据读取结果对它们执行更新。这些事务中的每一个都看不到另一个事务的修改。

      查看“serializable”下的postgresql wiki以获取更详细的示例。

    • 更新问题:

      这个问题我不太清楚。

      可序列化事务采用特殊的“si”锁,它跟踪读写访问并在提交后生存。它们不会阻止其他会话,但用于确定是否存在 可以 是一场冲突。可序列化的隔离级别只有在 全部的 并发事务使用可序列化的隔离级别。

        2
  •  0
  •   a_horse_with_no_name    7 年前

    关于中的问题 更新

    数据库是否决定可序列化事务的结果,就像其他事务也是以可序列化隔离方式运行的一样?”

    答案是不。

    仅在可序列化隔离级别的并发事务之间验证可序列化性。 . 例如,假设两个事务t1和t2交错如下:

    T1: begin
    T1: set transaction isolation level read committed;
    T1: update addresses set street = 'Sun street' where id = 1
    T2: begin
    T2: set transaction isolation level serializable;
    T2: select street from addresses where id = 1
    T2: update addresses set street = 'Sea street' where id = 2
    T1: select street from addresses where id = 2
    T1: commit
    T2: commit
    

    T1和T2都将提交。但是,如果T1设置为可序列化隔离,则T2将中止。