【问题标题】:What's the difference between DbUpdateConcurrencyException and 40001 postgres code?DbUpdateConcurrencyException 和 40001 postgres 代码有什么区别?
【发布时间】:2021-12-08 03:26:43
【问题描述】:
我有两笔交易。
首先,我选择一个实体,进行验证,将客户端文件提供的上传到 S3,然后使用有关 S3 文件的信息更新该实体。
第二笔交易只是删除该实体。
现在,假设有人调用了第一个事务,然后立即调用了第二个事务。第二个会更快,第一个会抛出DbUpdateConcurrencyException,因为更新查询中不再存在选定的实体。
当我的交易有IsolationLevel.ReadCommited 时,我得到DbUpdateConcurrencyException。但是如果我设置 IsolationLevel.Serializable 它会抛出 InvalidOperationException 和 40001 postgres 代码。有人可以解释为什么我会得到不同的错误,因为在我看来结果应该是相同的,因为这两个错误都是通过更新不存在的实体调用的?
【问题讨论】:
标签:
postgresql
exception
concurrency
entity-framework-core
【解决方案1】:
40001 错误对应于 SQLSTATE serialization_failure(请参阅table of error codes)。
它是由数据库引擎在检测到有并发事务时以可序列化隔离级别生成的,并且该事务可能产生了如果并发事务已串行运行则无法获得的结果。
使用IsolationLevel.ReadCommited时,是不可能得到这个错误的,因为选择这个隔离级别恰恰意味着客户端不希望数据库做这些隔离检查。
另一方面,DbUpdateConcurrencyException 可能不是由数据库引擎生成的。它由实体框架生成。数据库本身可以通过 UPDATE 更新零行,这不是 SQL 级别的错误。
我认为如果数据库首先出错,你会得到序列化失败,如果数据库没有出错,则会出现 DbUpdateConcurrencyException 错误,但按分层顺序排列的第二层(EF)会出错。
在可序列化隔离级别处理序列化失败的典型方法是客户端在收到40001 错误时重试事务。重试的事务将有一个全新的数据视图,并有望通过(否则,重试时循环)。
在较小的隔离级别(如Read Committed)处理并发的典型方法是在访问对象之前显式锁定对象以强制并发事务的序列化。