Patrick Böker
Patrick Böker

Reputation: 3253

Make Hibernate fail on missing transaction

I'm using Hibernate 5.2.1 and Spring 4.3.0

My current understanding is:

I have spent way too much time on not so merry bug hunts that ended in me realizing I was missing a @Transactional annotation, missed to configure a sensible transaction mode or failed to configure a transaction manager in Spring.

I do not want to engage in the mind-numbing activity of memorizing to never forget to painstreakingly check my transaction code.

I do want my software to be robust enough to tell me when I am doing something stupid or am forgetting something and not just silently fail and drop into an undefined behaviour mode.

Is it possible to make hibernate loudly complain when it's missing a transaction?

Am I approaching this the wrong way? Have I misunderstood anything?


Just for reference:

Upvotes: 0

Views: 724

Answers (1)

Yasser Zamani
Yasser Zamani

Reputation: 2500

Hibernate community says that working outside of transaction might cause unpredictable behavior. This is because Hibernate will open transaction, but it won't close it on its own, thus connection will be returned to the Connection Pool with transaction being not committed. What happens then? JDBC keeps silence, thus this is implementation specific (MySQL rolls back transaction, Oracle afair commits it). This also can be configured on Connection Pool level (e.g. C3P0 gives you such an option, rollback by default).

Is it possible to make hibernate loudly complain when it's missing a transaction?

You need to set the logging threshold to DEBUG for the following classes:

  1. For JDBC transactions (e.g. RESOURCE_LOCAL)

    • For SLF4J logging:

      <logger name="org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction" level="debug"/>
      
    • For Log4j:

      <logger name="org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction">
         <level value="DEBUG"/>
      </logger>
      
  2. For JTA transactions

    • For SLF4J logging:

      <logger name="org.hibernate.engine.transaction.internal.jta.JtaTransaction" level="debug"/>
      
    • For Log4j:

      <logger name="org.hibernate.engine.transaction.internal.jta.JtaTransaction">
         <level value="DEBUG"/>
      </logger>
      

In the logs you will see the following entries:

  • when the transaction starts:

    DEBUG [Alice]: o.h.e.t.i.j.JdbcTransaction - initial autocommit status: true
    DEBUG [Alice]: o.h.e.t.i.j.JdbcTransaction - disabling autocommit
    
  • when the transaction ends:

    DEBUG [Alice]: o.h.e.t.i.j.JdbcTransaction - committed JDBC Connection
    DEBUG [Alice]: o.h.e.t.i.j.JdbcTransaction - re-enabling autocommit
    

It's better to activate the DEBUG level for as few classes as possible, because otherwise your logs size will increase dramatically.

Am I approaching this the wrong way? Have I misunderstood anything?

If you may forget @Transactional in somewhere, try hibernate with autocommit=true which fails hardly on stupid codes and remembers you. Or you may use aspectj to make all DAOs methods transactional.

Upvotes: 1

Related Questions