Search code examples
javajpajavabeanspersiststateless

Persistence does not ocur in a stateless bean, using JPA when duplicate key exception is thrown


In a stateless bean, i´ve persisted a customer, but when I try to persist an entity product, this trows a duplicate key exception. So the customer is not persisted in db. Why is that?

@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')
}

Output: duplicate key exception persisting product

My question is:

  • Why customerEntity and prod1 are not persisted in db? The exception is handled.

I know that a solution is to ask before trying to persist, but I dont want to do that.


Solution

  • The best that can be done for this is to answer the question asked: Why.

    JPA EntityManager persist is defined in such a way that it is required to thrown an exception if the entity already exists - either an ntityExistsException immediately if it can be determined upfront, or any other persistence exception later on such as if it performs an insert during delayed synchronization to the database (ie flush or transaction commit).

    These exceptions are not recoverable for the EntityManager, as it cannot determine what else in the context made it in - if by chance you were able to continue with the transaction, it would be required to re attempt to insert the duplicate Entity since it is within the context. It would seem that JPA took the approach of requiring the user to obtain a new context and retry rather than define additional overhead to providers (and users) to clear out particular objects on errors such as this.

    What is usually done is an existence check before calling persist. In some cases, this is just a check that the Entity in question has an Identifier - if this is DB assigned, this is sometimes more than enough to know if it should use persist or perform some additional, more expensive check to determine if it should be inserted or ignored. There is no insert or ignore in JPA - but some providers do support issuing queries outside of the JPA context for you that would achieve the same ends.