In this post I’ll create a placeholder that I’ll keep updating in the future accumulating Spring Transaction Management best practises that I find along the way:
- Keep the
@Transactionaldefinition at the Service layer and not the DAO layer. Service beans might use multiple DAOs ACID-ly under the same transaction. If otherwise transaction management is defined at the DAO level, Service beans will pay the price of creating multiple transactions for a conceptually grouped operation let alone the data inconsistencies we’ll risk having not defining ACID Service operations.
- Further underlying the previous point we can define
@Transactional(propagation = Propagation.MANDATORY)at the class level of our DAOs, therefore enforcing the consumers of our DAOs to initiate transaction management.
- Know what are the defaults of the
@Transactionalannotation and don’t just use it by faith. Namely, if not specified otherwise, propagation is set to
Propagation.REQUIREDwhich means use an existing transaction otherwise create a new one; isolation is set to
Isolation.DEFAULTthat is defined by the underlying DB default which normally results to
readOnlyflag is switched off by default;
rollbackForcan be defined for a
Throwableclass but beware: by default rollback occurs only if a
RuntimeExceptionis thrown unless this parameter is setup.
- Be careful of the
@Transactional(readOnly = true, propagation=Propagation.REQUIRED)will throw an exception upon a JDBC insert/update command within that transaction, it wouldn’t have the expected behavior on an insert/update ORM operation where the operation will unintuitively go through and be committed successfully. Under an ORM environment use the flag along with
Propagation.SUPPORTS. In that case we won’t have to pay for the cost of creating a new transaction simply for a select operation unless there is one in place. Or even still consider ditching the whole
@Transactionalmanagement for select operations.
- Be careful when using
Propagation.REQUIRES_NEWthat is not in the top level. It causes problems more times than not. Since every time a new transaction is wrapping that aspect, in cases where multiple
REQUIRES_NEWs are included within the same transactional service method in cases of a rollback
ACIDis not respected and inconsistent data are left in the DB. On the other hand, just using it on the top level of the transaction method is fine and actually equates the default