答案 0 :(得分:1)
我必须同意@duffymo关于在启动交易之前进行验证。处理数据库异常并将其呈现给用户是相当困难的。
你得到分离异常的原因很可能是因为你认为你已经写了一些东西到数据库,然后你调用remove on或刷新对象,然后你尝试再写一些东西。
您需要做的是创建一个long-running conversation
,flushMode
设置为MANUAL
。
然后你开始持久化,然后你可以执行验证,如果可以,你再次坚持。完成后,一切都很好,你打电话给entityManager.flush()
。这会将所有内容保存到数据库中。
如果出现故障,你就不要冲洗了。您只需return null
或"error"
并留言。让我给你看一些伪代码。
假设您有一个人员和组织实体。 现在,您需要在将人员安排到组织之前存储人员。
private Person person;
private Organization org;
@Begin(join=true,FlushMode=MANUAL) //yes syntax is wrong, but you get the point
public String savePerson() {
//Inside some save method, and person contains some data that user has filled through a form
//Now you want to save person if they have name filled in (yes I know this example should be done from the view, but this is only an example
try {
if("".equals(person.getName()) {
StatusMessages.instance().add("User needs name");
return "error"; //or null
}
entityManager.save(person);
return "success";
} catch(Exception ex) {
//handle error
return "failure";
}
}
请注意,我们现在保存人员,但我们还没有刷新交易。但是,它将检查您在entitybean上设置的约束。 (@NotNull,@ NotEmpty等)。所以它只会模拟一次保存。
现在你为个人保存组织。
@End(FlushMode=MANUAL) //yes syntax is wrong, but you get the point
public String saveOrganization() {
//Inside some save method, and organization contains some data that user has filled through a form, or chosen from combobox
org.setPerson(person); //Yes this is only demonstration and should have been collection (OneToMany)
//Do some constraint or validation check
entityManager.save(org);
//Simulate saving org
//if everything went ok
entityManager.flush() //Now person and organization is finally stored in the database
return "success";
}
在这里你甚至可以把东西放在try catch
中,只有在没有异常的情况下才会返回成功,这样你就不会被抛到错误页面。
<强>更新强>
你可以试试这个:
@PersistenceContext(type=EXTENDED)
EntityManager em;
这将使有状态bean具有EJB3扩展持久化上下文。只要bean存在,查询中检索的消息就会保持在托管状态,因此对有状态bean的任何后续方法调用都可以更新它们,而无需对EntityManager进行任何显式调用。这可能会避免您的LazyInitializationException。
你现在可以使用了
em.refresh(user);
答案 1 :(得分:0)
我认为验证应该在事务发起之前完成。
答案 2 :(得分:0)
我最近以各种形式面对这种情况。
我找到的最好的方法是将你拥有的对象视为一个值对象(它基本上是在回滚之后)。要从数据库中删除它,请使用find的id(它不会进入数据库,因为它几乎肯定会被缓存)找到它的“附加”双胞胎,然后删除返回的对象。
类似于更新:获取新副本并进行更新。
这有点麻烦,但它避免了长时间的交易以及与之相关的所有邪恶锁定问题。