Java 使用Hibernate防止违反唯一约束
我有一个类似于Java 使用Hibernate防止违反唯一约束,java,hibernate,unique-key,Java,Hibernate,Unique Key,我有一个类似于(id INTEGER,sometext VARCHAR(255),…)的表,其中id作为主键,并且对sometext有一个唯一的约束。它在web服务器中使用,其中请求需要找到与给定的sometext对应的id(如果存在),否则将插入新行 这是此表上的唯一操作。此表上没有更新和其他操作。它的唯一目的是持久化遇到的sometext值的数量。这意味着我不能删除id并使用sometext作为主键 我做了以下工作: 首先,我查阅自己的缓存以避免任何数据库访问。几乎总是这样,我就完蛋了 否
(id INTEGER,sometext VARCHAR(255),…)
的表,其中id
作为主键,并且对sometext
有一个唯一的约束。它在web服务器中使用,其中请求需要找到与给定的sometext
对应的id
(如果存在),否则将插入新行
这是此表上的唯一操作。此表上没有更新和其他操作。它的唯一目的是持久化遇到的sometext
值的数量。这意味着我不能删除id
并使用sometext
作为主键
我做了以下工作:
- 首先,我查阅自己的缓存以避免任何数据库访问。几乎总是这样,我就完蛋了
- 否则,我使用Hibernate条件通过
查找行。通常情况下,这是有效的,我也完成了sometext
- 否则,我需要插入新行
sometext
。然后会出现ConstraintViolationException
异常。我需要像插入忽略或插入之类的内容。。。在重复密钥更新时(Mysql语法)或(Firebird语法)
我想知道有什么选择
AFAIK Hibernate
merge
仅在PK上工作,因此不合适。我想,本机查询可能有帮助,也可能没有帮助,因为当第二次插入发生时,它可能会提交,也可能不会提交。让数据库来处理并发性。仅为插入新行而启动辅助事务。如果由于ConstraintViolationException而失败,只需回滚该事务并读取新行。只需让数据库处理并发。仅为插入新行而启动辅助事务。如果由于ConstraintViolationException而失败,只需回滚该事务并读取新行。如果重复的可能性很高,则不确定这是否可以很好地扩展,如果某些百分比(取决于数据库)的事务无法通过插入,然后重新选择,则需要进行大量额外的工作
第二个事务使事务添加新文本所需的时间最小化,假设数据库正确支持它,线程1事务可能会导致线程2 select/insert挂起,直到提交或回滚线程1事务。总体数据库设计也可能影响事务吞吐量
我不一定质疑为什么有些文字不能成为PK,我想知道为什么你需要打破它。当然,如果某些文本记录很大,那么大容量可能会大大节省空间,这几乎像是在尝试模拟lucene索引,以提供完整的文本值列表。如果复制的可能性很高,则不确定这是否能很好地扩展,如果复制的可能性很高,则需要大量额外工作(取决于数据库)的事务必须插入失败,然后重新选择 第二个事务使事务添加新文本所需的时间最小化,假设数据库正确支持它,线程1事务可能会导致线程2 select/insert挂起,直到提交或回滚线程1事务。总体数据库设计也可能影响事务吞吐量
我不一定质疑为什么有些文字不能成为PK,我想知道为什么你需要打破它。当然,如果某些文本记录很大,那么大容量可能会大大节省空间,这几乎就像你试图模拟lucene索引来为你提供一个完整的文本值列表。我不明白为什么你不能使用sometext作为主键。另外,为什么你不能捕获ConstraintViolationException(并忽略它)?@Thilo 1。因为我需要一个数字而不是文本。这就是为什么我使用
id
。也许我可以使用sometext
并将数字存储在另一列中(我可以通过其他方式保证唯一性)。++2.如果我知道这不是由其他原因引起的,我会的。但表名在异常中不可用。此外,它发生在SessionImpl.flush
(而不是INSERT)中,这很可能意味着没有存储任何内容。Re:2那么您在同一事务中执行其他操作?这是必要的吗?或者只是在@Transactional(propagation=propagation.REQUIRES_NEW)
下运行编号,让它在自己的单独事务中运行。我不明白为什么不能使用某些文本作为主键。另外,为什么不能捕获ConstraintViolationException(并忽略它)?@Thilo 1。因为我需要一个数字而不是文本。这就是为什么我使用id
。也许我可以使用sometext
并将数字存储在另一列中(我可以通过其他方式保证唯一性)。++2.如果我知道这不是由其他原因引起的,我会的。但表名在异常中不可用。此外,它发生在SessionImpl.flush
(而不是INSERT)中,这很可能意味着没有存储任何内容。Re:2那么您在同一事务中执行其他操作?这是必要的吗?或者只是在@Transactional(propagation=propagation.REQUIRES_NEW)
下运行编号,让它在自己的单独事务中运行。这里我不关心性能,因为几乎所有内容都被缓存覆盖,重复项将非常少。仅供参考,我正在对请求主机地址进行编号。它们很短,所以我不需要节省空间,但我也想将它们的列表保存在数据库中。只有当新客户机(或共享IP的两个客户机)同时发出两个请求时,才会发生重复,除非在测试时,否则这种情况可能永远不会发生。在这里,我并不关心性能,因为缓存几乎涵盖了所有内容,重复的情况将非常罕见。仅供参考,我正在为请求编号