I have a Spring Boot application where I have a thin layer between the Controller and the Service which's only purpose it to try-catch and if an exception is thrown, to persist the failed entity with a JpaRepository, for subsequent inspection. I designed my "interceptor" like:
@Transactional
public void upload(byte[] bytes) {
try {
service.upload(bytes);
} catch (Exception e) {
failRepo.save(new Failure(bytes, e)); // code trimmed for brevity
throw e;
}
}
And my service method looks like:
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void upload(byte[] bytes);
What I expect is that, in case of an exception thrown in the service, the inner transaction will be rollbacked, the exception will pop out and the outer transaction will persist my data, but the hibernate logs show that for some reason the outer transaction also rollbacks and the failure data is not persisted. Do I need another propagation level on the outer layer also?
Edit: the relevant logs
o.s.o.h.HibernateTransactionManager : Creating new transaction with name [com.company.interceptor.upload]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.o.h.HibernateTransactionManager : Opened new Session [SessionImpl(480607911<open>)] for Hibernate transaction
o.h.e.t.internal.TransactionImpl : On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
o.h.e.t.internal.TransactionImpl : begin
o.s.o.h.HibernateTransactionManager : Exposing Hibernate transaction as JDBC [org.springframework.orm.hibernate5.HibernateTransactionManager$$Lambda$1317/0x0000000800d0c440@52318830]
o.s.o.h.HibernateTransactionManager : Found thread-bound Session [SessionImpl(480607911<open>)] for Hibernate transaction
o.s.o.h.HibernateTransactionManager : Suspending current transaction, creating new transaction with name [com.company.service.upload]
o.s.o.h.HibernateTransactionManager : Opened new Session [SessionImpl(1041560268<open>)] for Hibernate transaction
o.h.e.t.internal.TransactionImpl : On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
o.h.e.t.internal.TransactionImpl : begin
o.s.o.h.HibernateTransactionManager : Exposing Hibernate transaction as JDBC [org.springframework.orm.hibernate5.HibernateTransactionManager$$Lambda$1317/0x0000000800d0c440@778c9da3]
------ other irrelevant for us logs
o.s.o.h.HibernateTransactionManager : Initiating transaction rollback
o.s.o.h.HibernateTransactionManager : Rolling back Hibernate transaction on Session [SessionImpl(1041560268<open>)]
o.h.e.t.internal.TransactionImpl : rolling back
o.s.o.h.HibernateTransactionManager : Closing Hibernate Session [SessionImpl(1041560268<open>)] after transaction
o.s.o.h.HibernateTransactionManager : Resuming suspended transaction after completion of inner transaction
stomAnnotationTransactionAttributeSource : Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
o.s.o.h.HibernateTransactionManager : Found thread-bound Session [SessionImpl(480607911<open>)] for Hibernate transaction
o.s.o.h.HibernateTransactionManager : Participating in existing transaction
org.hibernate.engine.spi.ActionQueue : Executing identity-insert immediately
org.hibernate.SQL : insert into failure_table (content_type, created_time, exception_message, bytes, user_agent) values (?, ?, ?, ?, ?)
o.h.id.IdentifierGeneratorHelper : Natively generated identity: 15
o.h.r.j.i.ResourceRegistryStandardImpl : HHH000387: ResultSet's statement was not registered
o.s.o.h.HibernateTransactionManager : Initiating transaction rollback
o.s.o.h.HibernateTransactionManager : Rolling back Hibernate transaction on Session [SessionImpl(480607911<open>)]
o.h.e.t.internal.TransactionImpl : rolling back
o.s.o.h.HibernateTransactionManager : Closing Hibernate Session [SessionImpl(480607911<open>)] after transaction