Search code examples
javaspringhibernatejpa

Improving performance of a generic method for updating batch and to sync with database and cache


I'm writing method to update batch using entity manager (Eclipselink as a provider).

One approach I found here: Batch updates in JPA (Toplink) and here: JPA - Batch/Bulk Update - What is the better approach?.

But I'm not using spring Data JPA. If I use JPQL then the entity will not be added to cache (is it right). I'm using the following approach. But it is slower. Is there any other approach I can use?

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public <T> void updatetBatch(List<T> list) {
    if (list == null || list.isEmpty())
        throw new NullPointerException();
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    final int BATCHLIMIT = 50;

    try {
        int size = list.size();
        for (int i = 0; i < size; i++) {
             //Using find as it will make entity managed.
            Object found=entityManager.find(list.get(i).getClass(), this.getPrimaryKey(list.get(i)));
            if(found!=null)
            entityManager.merge(list.get(i));
            if (i % BATCHLIMIT == 0) {
                entityManager.flush();
                entityManager.clear();
            }
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        entityManager.close();
    }
}
private Object getPrimaryKey(Object object) {
    return entityManagerFactory.getPersistenceUnitUtil().getIdentifier(object);
}

Solution

  • Here is your modified code,

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public <T> void updatetBatch(List<T> list) {
        if (list == null || list.isEmpty())
            throw new NullPointerException();
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        final int BATCHLIMIT = 50;
    
        try {
            int size = list.size();
    
            for (int i = 0; i < size; i++) {
             Object primaryKeyObj = this.getPrimaryKey(list.get(i));
                 //Using find as it will make entity managed.
            T entityObject = list.get(i);
                Object found = entityManager.find(entityObject.getClass(), primaryKeyObj);
                if(found!=null) {
    
                    entityManager.merge(entityObject);
            } else{
            entityManager.persist(entityObject);
            }   
                if (i % BATCHLIMIT == 0) {
                    entityManager.flush();
                    entityManager.clear();
                }
            }
    
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            entityManager.close();
        }
    }
    private Object getPrimaryKey(Object object) {
        return entityManagerFactory.getPersistenceUnitUtil().getIdentifier(object);
    }