5

I have a heavy operation, which is read only. This is all mapped by hibernate, in a spring boot application. Hibernate spends 6seconds flushing my entities, when there is no mutation of any sort. This is simply a get operation.

I am trying to stop hibernate from spending that 6 second, flushing redundantly.

I put hibernate flush mode to MANUAL/NEVER. But it didn't make any difference.

The property is set correctly, but hibernate stats still show the flushing, count, and the time spent.

Arash
  • 11,697
  • 14
  • 54
  • 81
  • Have you considered marking the entities as `@Immutable` to see if that improves performance for you if they truly are _read-only_ or are you merely trying to prevent the flush before a read-only query? – Naros Jun 18 '18 at 16:53
  • That is an idea. But a bit of work, as the entities are not really immutable. Only in case of this flow, they don't change. – Arash Jun 19 '18 at 00:14

1 Answers1

3

There are several ways to do it. You may try: org.springframework.transaction.annotation.Transactional annotation set to read-only:

@Transactional(readOnly = true)

Which in case of Hibernate, it sets the JDBC transaction into a read-only mode and FlushMode.NEVER. Here details: https://stackoverflow.com/a/1712328/5810648

Also, it is possible to disable dirty-check calling setReadOnly(true) on Hibernate query or call setHint("org.hibernate.readOnly", true) on JPA query. According to doc :

Hibernate will never dirty-check them or make changes persistent ( eg. new Boolean(true) ), default to false

http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html#d0e1215

Another way is to use stateless session for that heavy operation. Here is details: https://stackoverflow.com/a/5497077/5810648

Ihor Rybak
  • 3,091
  • 2
  • 25
  • 32
  • I tried read only transactions, they didn't do the job somehow. I also tried setting flush mode to false manually. That also didn't cut it. I guess the problem is spring boot is creating the entity manager JPA way, and it somehow bypasses these settings. I am not sure though. – Arash Jun 21 '18 at 01:16
  • I confirm that putting `@Transactional(readOnly=true)` calls `setHibernateFlushMode(MANUAL)` (not NEVER) on the Hibernate session. Verified by a `@SpringBootTest` annotated on the test method, `TransactionSynchronizationManager.isCurrentTransactionReadOnly()` was true as expected, and `entityManager.unwrap(Session.class).getHibernateFlushMode()` returned MANUAL. This was with spring-tx:5.0.8 and hibernate-core:5.2.17.FINAL – Andrew Spencer Oct 05 '18 at 08:00
  • But note, when you perform an *explicit* `saveAndFlush(entity)`, the behaviour may be unexpected. Within `@Transactional(readOnly=true)`, the entity will not be persisted, and there will be no exception. Within `@Transactional(readOnly=true, propagation=SUPPORTS)`, again no exception, but the entity *will* be persisted! (This is because the operation executes non-transactionally.) – Andrew Spencer Oct 05 '18 at 08:25