如何使用 Hibernate 模拟 upsert 行为?

发布于 2024-09-18 11:03:07 字数 318 浏览 4 评论 0原文

我正在编写一个应用程序,将第三方数据源的实体同步到我们自己的架构中,中间有一个转换/映射步骤。我使用 Hibernate 来表示并持久保存我们自己的模式中的实体。我遇到的一个问题是我的一个表上有一个唯一的多列键。我希望看到的行为类似于更新插入:当 Hibernate 去持久化一个实体并检测到唯一约束违规时,它会进行更新。我们正在使用 MySQL,它提供了 INSERT ... ON DUPLICATE KEY UPDATE 语法,但我不确定 Hibernate 如何或是否可以使用它?

我想我总是可以尝试插入,如果我发现异常则进行更新,但这似乎很糟糕并且不是最理想的。有什么干净的方法可以做到这一点吗?

I'm writing an application that sync's entities from a third party datasource into our own schema, with a transformation/mapping step in between. I'm using Hibernate to represent and persist the entities in our own schema. A problem I'm running into is that I have a unique multi-column key on one of my tables. The behavior I would like to see is analogous to an upsert: when Hibernate goes to persist an entity and detects a unique constraint violation, it does an update instead. We are using MySQL, which provides an INSERT ... ON DUPLICATE KEY UPDATE syntax, but I'm not sure how or if Hibernate can be made to make use of it?

I suppose I could always try the insert, and if I catch an exception do an update, but that seems hacky and suboptimal. Any tips on a clean way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

╰つ倒转 2024-09-25 11:03:07

我们正在使用 MySQL,它提供了 INSERT ... ON DUPLICATE KEY UPDATE 语法,但我不确定如何或是否可以让 Hibernate 使用它?

看起来有人通过覆盖 sql-insert做到了这一点 code> Hibernate 为此实体使用的语句。如果您不介意不可移植(并且可能使用存储过程),请看一下。

我想我总是可以尝试插入,如果我捕获异常则进行更新,但这似乎很糟糕并且不是最理想的。有什么干净的方法可以做到这一点吗?

另一种选择是:

  1. 对唯一键执行选择
  2. 如果找到记录,则
  3. ;如果没有找到记录,则更新它;创建它,

但除非您在执行期间锁定整个表在此过程中,您可能会在多线程和分布式环境中面临一些竞争条件,并且步骤 #3 可能会失败。想象两个并发线程:

线程 1:

  • begin trans
  • 对某个键执行选择
  • 未找到记录
  • 创建记录
  • 提交

线程 2:

  • begin trans
  • 对同一个键执行选择
  • 未找到记录
  • 创建记录
  • 提交(失败! 因为线程 1 速度更快,并且现在存在具有相同唯一键的记录)

因此无论如何您都必须实现某种重试机制(在我看来,锁定整个表不是一个好的选择)。

We are using MySQL, which provides an INSERT ... ON DUPLICATE KEY UPDATE syntax, but I'm not sure how or if Hibernate can be made to make use of it?

It looks like someone did it by overriding the sql-insert statement used by Hibernate for this entity. If you don't mind not being portable (and probably using a stored procedure), have a look.

I suppose I could always try the insert, and if I catch an exception do an update, but that seems hacky and suboptimal. Any tips on a clean way to do this?

Another option would be to:

  1. perform a select on the unique key
  2. if you find a record, update it
  3. if you don't find a record, create it

But unless you lock the whole table(s) during the process, you can face some race condition in a multi-threaded and distributed environment and step #3 can potentially fail. Imagine two concurrent threads:

Thread 1:

  • begin trans
  • performs a select on a key
  • no record found
  • create a record
  • commit

Thread 2:

  • begin trans
  • performs a select on the same key
  • no record found
  • create a record
  • commit (FAIL! because thread 1 was faster and a record with the same unique key now exists)

So you would have to implement some kind of retry mechanism anyway (locking the whole table(s) is not a good option IMO).

假装爱人 2024-09-25 11:03:07

可以通过“选择...进行更新”来避免竞争条件

The race condition can be avoided by "select ... for update"

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文