Hibernate有重复的关键问题 [英] Duplicate key issue with Hibernate

查看:123
本文介绍了Hibernate有重复的关键问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Hibernate 4.0我有三个hibernate实体:

歌曲,CoverArt,CoverImage

歌曲代表音乐文件中,CoverImage表示图像,CoverArt用于将CoverImages与歌曲关联,一首歌曲可以包含多个封面图像。

Song和CoverArt具有由Hibernate自动生成的主键。但Cover Image主键手动完成,构造为图像数据的MessageDigest。我这样做是因为相同的图像可以被许多歌曲使用,我不希望在数据库中多次存储同一图像的单独实例,这也是因为可以从数据库中构建密钥,我可以在数据库中检查文件是否已经存在存在,如果这样检索它,而不是构建一个新的CoverImage。

麻烦的是我的应用程序是多线程的,Hibernate实际上并没有实际向数据库提交事情,所以线程1可能检查coverimage是否已经在数据库中,发现它并没有构造一个新的Song,CoverArt和CoverImage对象。但是当数据被提交到数据库时,一个CoverImage可能已经被一个单独的线程添加了,所以我得到一个异常,因为我的新CoverImage与现有的
具有相同的键



使用

  session.merge(coverImage); 

所以我认为会处理这个问题,但它似乎没有帮助

解决方案

没有可靠的方法来处理这种情况,除了重试失败的事务。



因此,如果由于 CoverImage 主键上的约束违规而获得事务回滚,则应重试该事务,假定 CoverImage 已经存在。请注意,您需要一个新的 Session 来执行此操作,因为Hibernate异常是无法恢复的。

merge()不能处理这个问题,因为它的原因在于事务隔离语义。在现代的基于 MVCC 的数据库管理系统中,每个事务都会看到自己的数据库快照。因此,并发事务可以对它们的快照进行冲突性更改(尽管它们不能对同一记录进行更改,因此这些更改必须是不相交的),并且这种冲突只能在提交期间由DBMS检测到,并且只有在导致约束违反,就像你的情况一样(没有约束冲突将被忽视,请参阅写出歪斜异常)。

由于 merge()在事务内部工作,所以无法查看其他事务在其快照中做了什么,因此无法克服这个问题。


Using Hibernate 4.0 I have three hibernate entities:

Song, CoverArt, CoverImage

Songs represents music file, CoverImage represents an image and CoverArt is used to relate CoverImages to Songs, a song can contain multiple cover images.

Song and CoverArt have a primary key generated automatically by Hibernate. But Cover Image primary key done manually, constructed as a MessageDigest of the image data. I do this because the same image can be used by many songs and I dont want seperate instances of the same image stored multiple times in the database, also because the key can be constructed from the data I can check in the database whether the file already exist and if so retrieve it rather than constructing a new CoverImage.

The trouble is my application is multithreaded and Hibernate doesnt actually commit things to the database immediaely, so thread 1 may check if the coverimage is already in the database, find that it isnt and construct a new Song, CoverArt and CoverImage objects. But by the time the data gets committed to the database a CoverImage may have been added by a seperate thread so I get an exception because my new CoverImage has the same key as an existing one

Im using

session.merge(coverImage);

so I thought that would handle this, but it doesn't seem to help

解决方案

There is no reliable way to handle this situation except for retrying the failed transaction.

So, if you get transaction rollback due to constraint violation on primary key of CoverImage you should retry the transaction assuming that CoverImage already exists. Note that you need a new Session to do it, because Hibernate exceptions are irrecoverable.

merge() cannot handle this issue because its causes lie deeper, in transaction isolation semantics. In modern MVCC-based DBMSes each transaction sees its own snapshot of the database. So, concurrent transactions can make conflicting changes to their snapshots (though they cannot make changes to the same record, so that these changes must be disjoint), and such a conflict can only be detected by DBMS during commit, and only if it causes constraint violation, as in your case (without a constraint conflict will be unnoticed, see write skew anomaly).

Since merge() works inside transaction it cannot see what other transaction do in their snapshots, therefore in cannot overcome this problem.

这篇关于Hibernate有重复的关键问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆