I am using JPA (with hibernate as the provider) in spring for a web-app.
I have a few methods that construct a complex object to be passed to the UI. As part of theses methods flow, a few select
SQL statements are executed. The problem is that the entity manager flushes before each select, this action takes a lot of time and is hindering the performance. Is there a way to prevent the entity manager from flushing before each select? (I don't care for stale data in the select selects above)
Thank you.
Here is my GenericDAO
@Repository
public abstract class GenericDAOWithJPA<T, ID extends Serializable> implements IGenericDAO<T, ID> {
private static final int MAX_RETRIES = 3;
private static final long WAIT_INTERVAL_MS = 1000;
static final Logger LOG = LoggerFactory.getLogger(GenericDAOWithJPA.class);
private Class<T> persistentClass;
protected EntityManager entityManager;
@SuppressWarnings("unchecked")
public GenericDAOWithJPA() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
@Override
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
this.entityManager.setFlushMode(FlushModeType.COMMIT)
}
@Override
public Class<T> getPersistentClass() {
return persistentClass;
}
/* (non-Javadoc)
* @see com.legolas.dao.IGenericDAO#find(ID)
*/
@Override
public T find(ID id) {
return entityManager.find(persistentClass, id);
}
@Override
public T getReference(ID id) {
return entityManager.getReference(persistentClass, id);
}
/* (non-Javadoc)
* @see com.legolas.dao.IGenericDAO#persist(T)
*/
@Override
public void persist(T entity) {
entityManager.persist(entity);
}
@Override
public void persist(List<T> entityList) {
for (T entity : entityList) {
persist(entity);
}
}
@Override
public T merge(T entity) {
return entityManager.merge(entity);
}
@Override
public void remove(T entity) {
entityManager.remove(entity);
}
@Override
@SuppressWarnings("unchecked")
public List<T> findAll() {
return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").getResultList();
}
@Override
@SuppressWarnings("unchecked")
public List<T> findInRange(int firstResult, int maxResults) {
return entityManager.createQuery("Select t from " + persistentClass.getSimpleName() + " t").setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}
@Override
public long count() {
return (Long) entityManager.createQuery("Select count(t) from " + persistentClass.getSimpleName() + " t").getSingleResult();
}
@Override
public void flush() {
this.entityManager.flush();
}
@Override
public void refresh(T entity) {
int retry = 0;
RuntimeException lastException = null;
do {
try {
this.entityManager.refresh(entity);
} catch (OptimisticLockException e) {
retry++;
lastException = e;
LOG.debug("OptimisticLockException retry {}", retry);
try {
Thread.sleep(WAIT_INTERVAL_MS);
} catch (InterruptedException e1) {
retry = MAX_RETRIES;
}
}
} while (lastException != null && retry < MAX_RETRIES);
}
}
The EntityManager. flush() operation can be used the write all changes to the database before the transaction is committed. By default JPA does not normally write changes to the database until the transaction is committed. This is normally desirable as it avoids database access, resources and locks until required.
And if you want to use a Hibernate-specific flush mode, you need to use Hibernate's Session to create your query and call its setHibernateFlushMode method.
Unlike save(), the saveAndFlush() method flushes the data immediately during the execution. This method belongs to the JpaRepository interface of Spring Data JPA.
Flushing the session forces Hibernate to synchronize the in-memory state of the Session with the database (i.e. to write changes to the database). By default, Hibernate will flush changes automatically for you: before some query executions. when a transaction is committed.
The following code disables flush before queries (flush would occur only before commit):
em.setFlushMode(FlushModeType.COMMIT);
You can also set your flush mode per query. It does not have to apply to the entire entity manager.
TypedQuery<Person> people = ... ;
people.setFlushMode(FlushModeType.COMMIT);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With