我已经在JBoss上使用hibernate / JPA几个月了,有一个问题我无法找到答案或解决方案。
似乎在创建新的实体bean时,我至少在调用EntityManager.persist(entityBean)之前无法进行查询,否则我收到以下错误:
TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
一个例子:
Job job = new Job();
Collection<Task> tasks = job.getTasks();
//entityManager.persist(job);
ActionPlan actionPlan = (ActionPlan) entityManager.createNamedQuery("ActionPlan.findByCommand").
setParameter("type", RunOperation.Install).getSingleResult();
Task task = Task.getTask(actionPlan);
task.setActionPlan(actionPlan);
tasks.add(task);
task.setJob(job);
我的问题是,如果没有先保存'job'(被注释掉的行),我就无法调用createNamedQuery。 ActionPlan与Job有关系,但NamedQuery(findByCommand)不与Job连接。令我困扰的是,当新创建的Job在这种情况下甚至不感兴趣时,我需要持久保存Job以查询数据库。
将调用persist()移动到代码段的末尾会产生上述错误。
我知道我正在处理的对象没有持久化,但是如果发生错误,持久化会导致无法回滚。
我相信有一个解决方案,所以如果有人有答案,我会非常感激。我错过了什么?
答案 0 :(得分:3)
您无法查询数据库中尚未存在的内容,这似乎是合乎逻辑的,不是吗?你可以做的是开始使用交易。在一个简单的例子中,您的会话将有一个事务,该事务将在您关闭会话之前打开。此时,将提交事务,并且所有更改都将保留。您只需要在出错时回滚您的交易。
P.S。 Here at the bottom你可以找到“典型的交易应该使用以下习语”。
Session sess = factory.openSession();
Transaction tx;
try {
tx = sess.beginTransaction();
//do some work
...
tx.commit();
}
catch (Exception e) {
if (tx!=null) tx.rollback();
throw e;
}
finally {
sess.close();
}
答案 1 :(得分:0)
我知道我无法查询尚未保留的内容 - 事实并非如此。我想要找到的是其他实体bean。不只是相同的类型,而是我拥有的任何类型的Entity bean。然后我得到了TransientObjectException。
我提到过我使用JBoss吗?我相信使用J2EE和JPA服务器控制着我的交易,而我想做的最后一件事就是干扰它了?!所以对我来说,除了使用requiresNew等,我不会搞乱交易 - 服务器会这么做。
也许我应该移动hibernate标签,因为实际上我正在使用JPA - JBoss使用hibernate。所以请在任何代码示例中与此相关。
答案 2 :(得分:0)
即使你坚持使用对象,你仍然可以回滚它。只有在调用EntityManager上的flush之后,才会同步到底层数据库。
答案 3 :(得分:0)
我认为Java EE 5教程中的答案和阅读内容给了我正确的答案。
与我的观点相反,persist()不会不刷新数据库,它只会将Entity bean移动到持久化状态。让我感到困惑的是,我注意到在调用persist之后,实体实际上仍被持久化到数据库中(并且可能在错误消息中出现'save'一词)。我接受了这个,因为flush被称为结束我的事务,但如果我得到了正确的,我仍然能够回滚 - 由我自己或服务器回滚异常。
所以我得出的结论是;只要与新实体相关,只要它与已经存在的另一个实体无关,就应该只调用persist。 然后维护事务,服务器更喜欢你;)
留给她的是,我仍然不明白为什么没有一切都处于持久状态我无法进行查询。