如果对象在数据库中不存在,则将其保存到数据库中(Hibernate和Spring)

10
我正在开发一个使用Hibernate/Spring框架的应用程序来管理一些电影。
Movie类与Genre类之间有一个多对多关系。这两个类都使用GeneratedValue注解生成id。
通过使用@Cascade(CascadeType.SAVE_UPDATE),可以通过movie对象保存genre对象。我已经在genre的type属性上放置了唯一约束(它是名称,例如“Fantasy”)。
现在我想让Hibernate检查是否已经存在一个type为“Fantasy”的genre,如果已经存在,则使用该genre的id而不是尝试插入新记录。(后者显然会引发错误)
最后,我需要的是类似于select-before-save的函数,而不仅仅是select-before-update。
在Hibernate中是否有这样的功能?
一些代码:
Movie类
@Entity
public class Movie {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

private String name;

@Lob
private String description;

@Temporal(TemporalType.TIME)
private Date releaseDate;

@ManyToMany
@Cascade(CascadeType.SAVE_UPDATE)
private Set<Genre> genres = new HashSet<Genre>();

.... //other methods

类型类

@Entity
public class Genre {

@Column(unique=true)
private String type;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id

....//other methods

你可以单独查询Genre实体,以查找是否已经存在“fantasy”类型,而不需要查询Movie。此外,您可以初始化genres集并对其进行迭代,以查看您的Genre是否存在其中。 - Gleeb
我有点希望Hibernate有一些这方面的功能,但是是的,那也是一个好的解决方案。正如@jordan002所说,我过度思考了这个问题。 - Mike
插入-如果存在是一种非常常见的操作...我发现Hibernate没有提供这个功能,我们不得不在代码中加入检查,我觉得很遗憾。 - Esko Piirainen
2个回答

7
您可能想多了。任何选择在更新或保存之前选择的选项都将导致2个数据库往返,第一个是选择,第二个是如果需要则插入。
如果您知道最初不会有很多流派,那么您有几个选项可以在大多数情况下用1个RT完成:
1. Hibernate二级缓存可以容纳许多甚至所有的类型,从而在检查存在性时进行简单的哈希表查找(假设为单个节点)。
2. 您可以假设您所有的流派已经存在,使用session.load(),并处理引用不存在的类型时抛出的行未找到异常作为新插入的结果。
但实际上,除非您谈论的是大量事务,否则简单的预查询操作不会影响性能。

3

我从未听说过在Hibernate的select-before-update/select-before-save中有这样的功能。

在这种情况下,您应该将Hibernate视为JDBC。

首先,如果您想知道是否拥有这样的流派,您应该查询它。

如果您有这个流派,则SAVE_UPDATE不会在您将其添加到电影中时创建新的流派。

如果您没有这个流派,则Hibernate将在数据库中创建一个新的Genre行,并为您添加到many_to_many表的连接。


+1 谢谢,但这可能会导致更多的查询。每添加一个新类型,我都需要重新查询数据库。 - Mike
1
选择在这样的小表上具有非常快的性能(您真正期望有多少流派)。另外,如果您在服务器上保留该表的实时记录,则只需缓存一次,并随后维护它,只要服务器存在即可。 - Gleeb

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