使用休眠功能根据唯一键查找或插入
我正在尝试编写一个方法,该方法将基于唯一但非主键返回Hibernate对象。如果实体已存在于数据库中,我想返回它,但如果它没有,我想创建一个新实例并在返回之前保存它。
更新:让我澄清一下,我正在编写此内容的应用程序基本上是输入文件的批处理处理器。系统需要逐行读取文件并将记录插入到数据库中。文件格式基本上是架构中多个表的非规范化视图,因此我所要做的是解析父记录,要么将其插入到数据库中,以便我可以获取新的合成键,或者如果它已经存在,请选择它。然后,我可以在其他表中添加其他关联记录,这些表具有回该记录的外键。
这很棘手的原因是每个文件都需要完全导入或根本不导入,即为给定文件完成的所有插入和更新都应该是一个事务的一部分。如果只有一个进程执行所有导入,这很容易,但是如果可能的话,我想在多个服务器上将其分解。由于这些约束,我需要能够留在一个事务中,但处理已经存在记录的异常。
父记录的映射类如下所示:
@Entity
public class Foo {
@Id
@GeneratedValue(strategy = IDENTITY)
private int id;
@Column(unique = true)
private String name;
...
}
我最初尝试编写此方法的方法如下:
public Foo findOrCreate(String name) {
Foo foo = new Foo();
foo.setName(name);
try {
session.save(foo)
} catch(ConstraintViolationException e) {
foo = session.createCriteria(Foo.class).add(eq("name", name)).uniqueResult();
}
return foo;
}
问题是,当我要查找的名称存在时,对 uniqueResult() 的调用会引发 org.hibernate.AssertionFailure 异常。完整的堆栈跟踪如下:
org.hibernate.AssertionFailure: null id in com.searchdex.linktracer.domain.LinkingPage entry (don't flush the Session after an exception occurs)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:82) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:190) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:147) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:219) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1185) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1709) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
at org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:369) [hibernate-core-3.6.0.Final.jar:3.6.0.Final]
有谁知道是什么原因导致引发此异常?休眠是否支持实现此目的的更好方法?
让我先发制人地解释为什么我首先插入,然后选择是否以及何时失败。这需要在分布式环境中工作,因此我无法在检查中同步以查看记录是否已存在和插入。执行此操作的最简单方法是让数据库通过检查每次插入时的约束冲突来处理此同步。