postgresql不允许两个不冲突的可序列化交易通过 我使用postgresql 14。创建下表: 创建表用户 (( ID串行主键, first_name varchar(255)不为空, last_name varchar(255)不为空 ); 插入

问题描述 投票:0回答:1
在两个单独的并发交易中执行两次陈述,隔离级别设置为可序列化的冲突。交易开始后来将:

the Update语句上的等待,直到交易较早开始提交
交易开始提交提交后立即犯下并发误差

begin isolation level serializable; update users set first_name = 'aa' where first_name = 'a'; commit;

    -- Concurrently, note it operates on last_name instead begin isolation level serializable; update users set last_name = 'aa' where last_name = 'a'; commit;
  • 为什么?在我看来,这两项交易似乎都不会违反任何非序列性不变性(这些交易可以按任何顺序执行,结果将是相同的),也可以创建任何因较低隔离级别而禁止的现象。 是因为隔离级别是用整个行锁实现的,这是一个泄漏的实现?
是的,发生冲突是因为
postgresql的可序列隔离级别使用谓词锁定和一种称为可序列化快照隔离(SSI)
的技术,该技术旨在
漏和预防异常,而不仅仅是使用行锁。

为什么这是发生的?

eve,尽管这两个交易更新了不同的列(
sql postgresql transactions transaction-isolation
1个回答
0
投票
vs.

last_name),但他们仍在修改同一行。 postgresqltracks读取/写依赖项确保数据库的最终状态可序列化,这意味着结果必须是按照某种序列顺序执行的。

serializable ryalation:

postgresql跟踪

利用冲突

使用
siread锁
(谓词锁)和
write-write依赖项.

如果两项交易在

SAMEROW上进行,则PostgreSQLcannot保证序列化性

  • 为什么它会发生冲突? transaction 1(T1)启动

    ,并从
  • first_name
  • 更新

    'a' 读和写入行,将其标记为其序列化集的一部分。

  • transaction 2(
'aa'

)启动,并从T2

更新
    last_name
  1. 也读和写同一行,即使列不同。
    
    当提交时,PostgreSQL检查是否在
    'a'
    具有serialization依赖性后开始的任何事务
    

      'aa'
    • T1取决于同一行,后Ql检测一个可能导致不可序列结果的危险周期。
  2. T1

    被迫流产,错误:
    T2
    
    

    为什么postgresql允许这两个交易?
    • 尽管它可以以任何方式订购交易,但thostgresql仍未分析列级的变化,它可以跟踪表在
    • T2
    表中的原子单位
  3. 。这是因为:
  4. postgresql通过可序列化快照隔离(SSI)实现可序列化的,该快照
    可防止使用依赖关系跟踪的异常。
    

    列级写作不是单独跟踪的
      ,因此对行的任何部分都视为依赖项的更新。
    • 如果允许两笔交易,则在更复杂的情况下可能会导致微妙的异常。
      
      
      
    如何避免这种冲突?
  5. eption1:使用可重复的读取

    如果您严格不需要序列化,则可以使用可重复的读取
    隔离:

    ERROR: could not serialize access due to read/write dependencies among transactions HINT: The transaction might succeed if retried.

    
    

usersprvents丢失了更新和不可重复的读数,但确实可以强制执行完整的序列化。

这种避免不必要的中断,同时仍提供强大的孤立水平 eption2:在开始第二次

之前提交第一笔交易
同时运行它们的目的是手动将它们进行序列化:

  1. BEGIN ISOLATION LEVEL REPEATABLE READ; UPDATE users SET first_name = 'aa' WHERE first_name = 'a'; COMMIT;

    由于他们没有同时运行,没有发生序列化冲突。

    发生冲突是不是因为全行锁,而是因为Postgresql的
  2. se序可隔离快照隔离(SSI)检测依赖性周期。由于两项交易都修改了同一行,因此postgresql
  3. cannot确保串行订单而不会滚动一个。使用可重复的阅读,仔细的订购或重试

    可以帮助避免此问题。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.