JPA – create-if-not-exists entity?

I’d like to write a method like <T> T getOrCreate(Class<T> klass, Object primaryKey)

This won’t be easy.

A naive approach would be to do something like this (assuming the method is running inside a transaction):

public <T> T findOrCreate(Class<T> entityClass, Object primaryKey) {
    T entity = em.find(entityClass, primaryKey);
    if ( entity != null ) {
        return entity;
    } else {
        try {
            entity = entityClass.newInstance();
            /* use more reflection to set the pk (probably need a base entity) */
            return entity;
        } catch ( Exception e ) {
            throw new RuntimeException(e);
        }
    }
}

But in a concurrent environment, this code could fail due to some race condition:

T1: BEGIN TX;
T2: BEGIN TX;

T1: SELECT w/ id = 123; //returns null
T2: SELECT w/ id = 123; //returns null

T1: INSERT w/ id = 123;
T1: COMMIT; //row inserted

T2: INSERT w/ name = 123;
T2: COMMIT; //constraint violation

And if you are running multiple JVMs, synchronization won’t help. And without acquiring a table lock (which is pretty horrible), I don’t really see how you could solve this.

In such case, I wonder if it wouldn’t be better to systematically insert first and handle a possible exception to perform a subsequent select (in a new transaction).

You should probably add some details regarding the mentioned constraints (multi-threading? distributed environment?).

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)