Hibernate + "ON DUPLICATE KEY" 逻辑

7
我正在寻找一种方法,根据由几个列组成的表的唯一键来保存或更新记录。我想要实现与INSERT ... ON DUPLICATE KEY UPDATE相同的功能 - 即盲目保存记录,并让DB/Hibernate插入一个新记录,或者如果唯一键已存在,则更新现有记录。
我知道可以使用@SQLInsert( sql="INSERT INTO .. ON DUPLICATE KEY UPDATE"),但我希望不编写自己的SQLs并让Hibernate完成工作。(我假设它将做得更好 - 否则为什么要使用Hibernate?)

2
你最好选择On Dup Key这条路线... - CarpeNoctumDC
我想现在确实只会使用ON DUP KEY... - Galz
3个回答

3
当您尝试插入违反约束的行时(包括唯一约束),Hibernate可能会抛出一个ConstraintViolationException异常。如果没有遇到该异常,您可能会遇到其他一些常规的Hibernate异常 - 这取决于Hibernate的版本以及Hibernate在使用的数据库类型和版本中将MySQL异常映射为Hibernate异常的能力(我没有在所有环境中进行过测试)。
只有在调用flush()后才会收到异常,因此您应该确保这也在try-catch块中。
我建议小心实现首先检查行是否存在的解决方案。如果多个会话同时更新表,则可能会出现竞争条件。两个进程以几乎相同的时间读取该行以查看它是否存在;他们都检测到它不存在,然后他们都尝试创建一个新行。根据谁赢得比赛,其中一个将失败。
更好的解决方法是首先尝试插入,如果失败,则假定它已经存在。但是,一旦您遇到异常,就必须回滚,因此这将限制您如何使用此方法。

0

对我来说,这似乎不是一个清晰的方法。最好先查看是否存在具有给定键的实体。如果存在,则更新并保存它;如果不存在,则创建一个新实体。

编辑

或者考虑一下merge()是否符合您的要求:

  • 如果当前与会话相关联的标识符具有相同的持久实例,则将给定对象的状态复制到持久实例上
  • 如果当前没有与会话相关联的持久实例,则尝试从数据库加载它,或创建一个新的持久实例
  • 返回持久实例
  • 给定实例不会与会话相关联,它仍然是分离的

< http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html


当使用 'ON DUPLICATE KEY' 时,由于 DB 本身需要先检查行是否存在才能进行更新/插入操作,因此我不确定。 - Stijn Geukens
另外,我不确定所有的DB服务器(如MS-SQL)是否支持ON DUPLICATE KEY。 - Stijn Geukens
我认为数据库将能够更有效地使用索引-如果我插入100条记录,则我可以循环遍历它们并运行100个不同的SELECT查询和100个不同的INSERT / UPDATE查询,或以某种方式使用 IN()? 对于我来说,这听起来更安全(在非常大的数据库中,我已经使用ON DUP KEY一段时间了,它非常高效)。 - Galz
@galz,你能否提供一下ON DUP KEY特性的链接? - Levente Pánczél
@LeventePánczél - https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html - Galz

-3
你可以使用Session类中的saveOrUpdate()方法。

8
saveOrUpdate()并不能解决这个问题,特别是在Galz所描述的使用情况下。saveOrUpdate会尝试更新,如果标识符被设置了(并且它不是assigned),并且如果是新的对象实例,它将尝试插入(无论数据库中是否存在具有相同标识符的记录)。 - jpkroehling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接