我有两个事务。首先,我选择一个实体,进行验证,将客户端文件提供的上传到S3,然后使用有关S3文件的信息更新该实体。第二个事务就是简单地删除这个实体。现在,假设有人调用了第一个事务,然后立即调用了第二个事务。第二个查询会进行得更快,第一个会抛出DbUpdateConcurrencyException
,因为所选实体在更新查询中不再存在。
我得到DbUpdateConcurrencyException
,当我的交易有IsolationLevel.ReadCommited
。但是,如果我设置IsolationLevel.Serializable
,它抛出InvalidOperationException
与40001 postgres代码。有人能解释为什么我得到不同的错误,因为在我看来,结果应该是相同的,因为两个错误调用更新不存在的实体?
40001
错误对应于SQLSTATEserialization_failure
(参见错误码表)。
当数据库引擎检测到存在并发事务时,它在可序列化隔离级别上生成,并且该事务可能产生了如果并发事务串行运行则无法获得的结果。当使用IsolationLevel.ReadCommited
时,不可能获得此错误,因为选择此隔离级别恰恰意味着客户端不希望数据库执行这些隔离检查。
另一方面,DbUpdateConcurrencyException
可能不是由数据库引擎生成的。它由实体框架生成。数据库本身没有问题,UPDATE更新零行,这不是SQL级别的错误。
我认为如果数据库首先出错,则会出现序列化失败,如果数据库没有出错,则会出现DbUpdateConcurrencyException错误,但分层顺序中的第二层(EF)会出现。
在可序列化隔离级别上,处理序列化失败的典型方法是客户端在获得40001
错误时重试事务。重试的事务将有一个数据的新视图,并且有望通过(否则,重试时会循环)。
Read Committed
这样的低隔离级别上处理并发的典型方法是在访问对象之前显式地锁定对象,以强制并发事务的序列化。