【问题标题】:Hibernate + "ON DUPLICATE KEY" logic休眠+“ON DUPLICATE KEY”逻辑
【发布时间】:2011-03-10 11:13:58
【问题描述】:

我正在寻找一种方法来保存或更新记录,根据由几列组成的表的唯一键)。

我想实现 INSERT ... ON DUPLICATE KEY UPDATE 使用的相同功能 - 意思是盲目地保存一条记录,让 DB/Hibernate 插入一条新记录,或者如果唯一键已经存在,则更新现有记录。

我知道我可以使用@SQLInsert( sql="INSERT INTO .. ON DUPLICATE KEY UPDATE"),但我希望不要编写自己的 SQL 并让 Hibernate 完成这项工作。 (我假设它会做得更好 - 否则为什么要使用 Hibernate?)

【问题讨论】:

  • 使用 On Dup Key 路线可能会更好...
  • 我想我现在确实会坚持使用 ON DUP KEY...

标签: java mysql hibernate duplicates


【解决方案1】:

当您尝试插入破坏约束(包括唯一约束)的行时,Hibernate 可能会抛出 ConstraintViolationException。如果你没有得到那个异常,你可能会得到一些其他一般的 Hibernate 异常——它取决于 Hibernate 的版本和 Hibernate 将 MySQL 异常映射到你正在使用的数据库版本和类型中的 Hibernate 异常的能力(我还没有在所有方面都测试过)。

您只会在调用flush() 后得到异常,因此您应该确保这也在您的 try-catch 块中。

我会小心实施首先检查该行是否存在的解决方案。如果多个会话同时更新表,您可能会得到竞争条件。两个进程几乎同时读取该行以查看它是否存在;他们都检测到它不存在,然后他们都尝试创建一个新行。一个人是否会失败取决于谁赢得了比赛。

更好的解决方案是先尝试插入,如果失败,则假设它已经存在。但是,一旦出现异常,您将不得不回滚,这将限制您使用此方法的方式。

【讨论】:

    【解决方案2】:

    这对我来说听起来并不像一个干净的方法。最好先查看具有给定键的实体是否存在。如果是,请更新并保存它,如果没有,请创建一个新的。

    编辑

    或者也许考虑一下 merge() 是否是您正在寻找的:

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

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

    【讨论】:

    • 我不确定,因为在使用“ON DUPLICATE KEY”时,数据库本身也需要先检查行的存在,然后再进行更新/插入。
    • 另外,我不确定是否所有数据库服务器(如 MS-SQL)都支持 ON DUPLICATE KEY。
    • 我认为数据库将能够更有效地使用索引 - 如果我插入 100 条记录,我可以这样做,我可以循环它们并运行 100 个不同的 SELECT 查询和100 个不同的 INSERT/UPDATE 查询,或者以某种方式使用IN ()?在我看来,它在数据库上更安全(我在非常大的数据库中使用ON DUP KEY 一段时间,它非常有效)。
    • @galz 请问ON DUP KEY指的是什么功能?
    【解决方案3】:

    您可以使用 Session 类中的 saveOrUpdate()。

    【讨论】:

    • saveOrUpdate() 确实解决了这个问题,特别是在 Galz 描述的用例中。 saveOrUpdate 将尝试更新,如果标识符已设置(它不是assigned),如果它是一个新的对象实例,将尝试更新insert(无论数据库中是否存在具有相同标识符的记录)。
    猜你喜欢
    • 1970-01-01
    • 2015-12-10
    • 2018-01-17
    • 2011-05-16
    • 1970-01-01
    • 2018-12-01
    • 2015-11-05
    • 2014-03-10
    • 2013-10-03
    相关资源
    最近更新 更多