【问题标题】:Prevent violating of UNIQUE constraint with Hibernate使用 Hibernate 防止违反 UNIQUE 约束
【发布时间】:2016-05-08 23:35:56
【问题描述】:

我有一个类似(id INTEGER, sometext VARCHAR(255), ....) 的表,其中id 作为主键,对sometext 有一个唯一约束。它用于网络服务器,其中请求需要找到与给定sometext 对应的id(如果存在),否则插入新行。

这是对该表的唯一操作。此表没有更新,也没有其他操作。它的唯一目的是持续不断地遇到sometext 的值。这意味着我不能删除id 并使用sometext 作为PK。

我执行以下操作:

  • 首先,我查阅自己的缓存以避免任何数据库访问。几乎总是这样,我已经完成了。
  • 否则,我使用 Hibernate Criteria 来查找 sometext 所在的行。通常,这行得通,我已经完成了。
  • 否则,我需要插入一个新行。

这很好用,除非有两个具有相同sometext 的重叠请求。然后ConstraintViolationException 结果。我需要INSERT IGNOREINSERT ... ON DUPLICATE KEY UPDATE(Mysql 语法)或MERGE(Firebird 语法)之类的东西。

我想知道有哪些选择?

AFAIK Hibernate merge 仅适用于 PK,因此不合适。我想,本机查询可能有帮助,也可能没有,因为它可能会在第二次 INSERT 发生时提交,也可能不会提交。

【问题讨论】:

  • 我不明白为什么你不能使用 sometext 作为 PK。
  • 另外,你为什么不能捕获 ConstraintViolationException(并忽略它)?
  • @Thilo 1. 因为我需要一个数字而不是文本。这就是我使用id 的原因。也许我可以使用sometext 并将数字存储在另一列中(我可以通过其他方式保证唯一性)。 +++ 2. 如果我知道它不是由其他原因引起的,我可以。但是表名在异常中不可用。此外,它发生在 SessionImpl.flush(而不是 INSERT)中,这很可能意味着没有任何内容被存储。
  • Re:2 所以你在同一个事务中做其他事情?有必要吗?
  • 或者只运行@Transactional(propagation = Propagation.REQUIRES_NEW)下的编号,让它在自己的单独事务中运行。

标签: java hibernate unique-key


【解决方案1】:

让数据库处理并发。启动一个纯粹用于插入新行的辅助事务。如果它因 ConstraintViolationException 而失败,只需回滚该事务并读取新行。

【讨论】:

    【解决方案2】:

    如果重复的可能性很高,不确定这是否可以很好地扩展,如果某些百分比(取决于数据库)的事务必须插入失败然后重新选择,则需要做很多额外的工作。

    辅助事务最小化事务添加新文本所需的时间长度,假设数据库正确支持它,线程 1 事务可能导致线程 2 选择/插入挂起,直到线程 1事务被提交或回滚。整体数据库设计也可能会影响事务吞吐量。

    我不一定会质疑为什么 sometext 不能成为 PK,想知道为什么您需要将其分解。当然,如果某些文本记录很大,大容量可能会大大节省空间,这几乎就像您在尝试模拟 lucene 索引来为您提供完整的文本值列表。

    【讨论】:

    • 我不关心这里的性能,因为几乎所有东西都被缓存覆盖了,重复的情况非常罕见。仅供参考,我正在对请求主机地址进行编号。它们相当短,所以我不需要节省空间,但我也想将它们的列表保存在数据库中。仅当 客户端(或两个共享 IP 的客户端)同时发出两个请求时才会发生重复,除非在测试时,否则这可能永远不会发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 2020-01-17
    • 2015-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多