在无状态 bean 中,我保留了一个客户,但是当我尝试保留一个实体产品时,这会引发重复的键异常。 所以客户没有持久化在数据库中。这是为什么?
@Stateless
public class WebUserServiceEjb {
public void addProductToCustomer(String customer, List<String> products) {
customerEntity = ... get customer with string customer
try {
em.persist(customerEntity);
em.flush();
em.refresh(customerEntity);
// this is ok
prod1 = ... get entity using string fromproducts list
em.persist(prod1);
// this is ok
prod2 = ... get entity using string from products list
em.persist(prod2); //this throws an exception
} catch (ConstraintViolationException e) {
System.out.println('duplicate key exception persisting product')
}
我的问题是:
我知道解决方案是在尝试坚持之前先询问,但我不想这样做。
对此最好的办法就是回答所提出的问题:为什么。
JPA EntityManager persist 的定义方式是,如果实体已经存在,则需要抛出异常 - 如果可以预先确定,则立即抛出 ntityExistsException,或者稍后执行任何其他持久性异常,例如如果它执行在延迟同步到数据库期间插入(即刷新或事务提交)。
这些异常对于 EntityManager 来说是不可恢复的,因为它无法确定上下文中的其他内容 - 如果您偶然能够继续事务,则需要重新尝试插入重复的实体,因为它是在上下文中。 JPA 似乎采取了要求用户获取新上下文并重试的方法,而不是为提供者(和用户)定义额外的开销来清除此类错误的特定对象。
通常做的是在调用 persist 之前进行存在性检查。在某些情况下,这只是检查相关实体是否具有标识符 - 如果这是数据库分配的,有时这足以知道是否应该使用持久性或执行一些额外的、更昂贵的检查来确定是否应该被插入或忽略。 JPA 中没有插入或忽略 - 但某些提供程序确实支持在 JPA 上下文之外发出查询,以达到相同的目的。