Often, developers forgotten the transactional behaviour of proxies Spring:
– by default, the transaction is rollbacked only in the case of runtime, unchecked exceptions (an instance or subclass of RuntimeException) and for Errors;
– the transaction is not rollbacked if a checked exception is thrown from a transactional method.

A good practice is to create 2 types of checked exceptions extending Exception:
– one for the rollback needs for example “BusinessMessageException extends Exception”,
– an other for the no-rollback needs for example “BusinessMessageExcWithoutRollback extends BusinessMessageException”,

and modify the transaction parameters of classes with

"@Transactional(readOnly = true, rollbackFor=BusinessMessageException.class)"

and depending on needs, the parameters of each transactional method with:

"@Transactional(readOnly = false, propagation = Propagation.REQUIRED, noRollbackFor=BusinessMessageExcWithoutRollback.class)"