ServiceStack OrmLite:.Save/SaveAsync 在主键上生成重复条目

ServiceStack OrmLite: .Save/SaveAsync generates Duplicate entry on PRIMARY key

我的印象是 OrmLite Save 方法进行了“更新插入”,如果 record/row 存在则更新,否则插入。 在 documentation for ServiceStack OrmLite 中,它表示:

Save and SaveAll will Insert if no record with Id exists, otherwise it Updates.

但是,有时我会收到重复输入错误:

Duplicate entry 'PresentationWorker.Presentations.CoreObjectListPresentation-Pres' for key 'presentationproducer.PRIMARY

POCO 有一个 Id 属性 即 PrimaryKey

[PrimaryKey]
[StringLength(512)]
public string Id { get; set; }

此外,MySQL 中的数据库有 Id 作为主键:

  1. 首先让我觉得奇怪的是错误信息,它表明PRIMARY字段中的值以CoreObjectListPresentation-Pres结尾,但它不是,它实际上比那个长,整个Id 字段中的值为 PresentationWorker.Presentations.CoreObjectListPresentation-PresentationWorkerModule:TED-RYZEN:37576

正在保存的 POCO 中的 Id 道具与数据库中已有的相同:

和数据库:

我想知道如果已经有一个具有相同值的 PRIMARY KEY 应该执行 Update,我是如何得到错误的?但是当我启用日志记录功能时,我可以看到 SQL 查询实际上是一个 INSERT,而不是 UPDATE:

SQL: INSERT INTO PresentationProducer (Id,PresentationType,ModuleChannelName,LastUpdatedTimestamp) VALUES (@Id,@PresentationType,@ModuleChannelName,@LastUpdatedTimestamp) PARAMS: @Id=PresentationWorker.Presentations.CoreObjectListPresentation-PresentationWorkerModule:TED-RYZEN:37576, @PresentationType=PresentationWorker.Presentations.CoreObjectListPresentation, @ModuleChannelName=PresentationWorkerModule:TED-RYZEN:37576, @LastUpdatedTimestamp=2021-11-21 09:09:02

我正在考虑某种形式的竞争条件,但我不确定这到底是怎么发生的。我试图在源代码中找到 SaveAsync,但没有找到它的相关代码。

当 Save 方法用于 MySQL 时,OrmLite 是否可以使用 INSERT ON DUPLICATE KEY UPDATE 方法进行改进?

(使用 ServiceStack 5.13.1、.NET5、VS2022、MySqlConnector 和数据库为 MySQL8)

OrmLite 在决定 db.Save* 是否应该插入或更新记录之前必须检查记录是否存在。这为以下可能性留下了空间:如果 2 个请求同时尝试同时保存相同的新记录,则如果第一个插入发生在第二个请求检查之后,则可能会出现竞争条件。

这通常是双重发布错误触发 2+ 个并发请求的结果。将其更改为使用显式 db.Insert*db.Update* 不会有帮助,因为您将获得与 2+ 插入相同的响应。

处理此问题的正确方法是在 OrmLite 尚不支持的每个 RDBMS 中使用本机更新插入功能,请vote for the feature request在实现该功能时收到通知。