Spring 3 JDBC transaction manager not working - spring

I am using Spring 3, MYSQL 5.5, tomcat 6. In my app i have 3 DAO methods executing one after another inside a service class method.
#Transactional(propagation = Propagation.REQUIRED, rollbackFor = {
Exception.class, RuntimeException.class })
myService(){
try {
dao1.delete();
dao1.update();
dao1.save();
} catch(){}
}
Dao1 -
delete() throws exp1{ ---- some code ----}
save() throws exp1{ ---- some code ----}
update() throws exp2{ ---- some code ----}
Now even if an exception is raised my transaction gets committed, like if update() raise an exception delete() and save() doesn't get rolledback. I tried looking into spring logs and i can see it has committed transaction after exception
20:00:29,071 DEBUG SQLErrorCodesFactory:198 - Looking up default SQLErrorCodes for DataSource [org.apache.tomcat.dbcp.dbcp.BasicDataSource#44755866]
20:00:29,078 DEBUG SQLErrorCodesFactory:216 - Database product name cached for DataSource [org.apache.tomcat.dbcp.dbcp.BasicDataSource#44755866]: name is 'MySQL'
20:00:29,079 DEBUG SQLErrorCodesFactory:174 - SQL error codes for 'MySQL' found
20:00:29,081 DEBUG SQLErrorCodeSQLExceptionTranslator:399 - Translating SQLException with SQL state '42S02', error code '1146', message [Table 'xxx.xxxx' doesn't exist]; SQL was [DELETE FROM xxxx WHERE xxxx=?] for task [PreparedStatementCallback]
20:00:29,086 DEBUG xxxServiceImpl:1022 - Returning result after deleting product : xxxx.xxxxx.xxxxx.xxx.ResultVO Object {Result: false, Error code: 1016, Error text: Error while deleting data. Please try again later}
20:00:29,094 DEBUG DataSourceTransactionManager:752 - Initiating transaction commit
20:00:29,097 DEBUG DataSourceTransactionManager:264 - Committing JDBC transaction on Connection [jdbc:mysql://localhost:3306/xxx?autoReconnect=true, UserName=root#localhost, MySQL-AB JDBC Driver]
20:00:29,113 DEBUG DataSourceTransactionManager:322 - Releasing JDBC Connection [jdbc:mysql://localhost:3306/xxx?autoReconnect=true, UserName=root#localhost, MySQL-AB JDBC Driver] after transaction
20:00:29,115 DEBUG DataSourceUtils:332 - Returning JDBC Connection to DataSource
If i put #Transactionl before DAO methods, transaction gets rolledback but i am getting 500 error, stating that transaction is already marked for rollback. Am i missing something here?

Remove the try {} catch {} block.
The transaction rollback will happen only if the exception is thrown back to the caller from the method.
In your case you are silently killing the exception using a empty try..catch block, so the exception is never propagated to the transaction manager, so the transaction manger never get the signal to rollback.
In case of annotating the dao, when the exception is thrown from the dao layer, the transaction proxy surrounding the dao method marks the attached transaction (created by the service layer) as rollback only, then when the control is returned from the service layer the transaction manager tries to commit the changes but finds that it is marked as read-only. That is why the error is coming.

Related

Suspected threading issues when using JaversAuditableAuditAsync

I am using Javers with Spring Hibernate JPA. The primary database is a MYSQL database with Javers connected to a seperate MongoDB server. I am not using Spring Data.
Everything works great with JaversAuditableAspect but I get the below errors when I use JaversAuditableAspectAsync.
I am using the default setup for the Async Javers.
#Bean
public JaversAuditableAspectAsync javersAuditableAspectAsync() {
return new JaversAuditableAspectAsync(javers(), authorProvider(), new EmptyPropertiesProvider(), javersAsyncAuditExecutor());
}
#Bean
public ExecutorService javersAsyncAuditExecutor() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("JaversAuditableAsync-%d")
.build();
return Executors.newFixedThreadPool(2, threadFactory);
}
I understand this is an experimental feature but performance is very important in the area I intend to use Javers. Any advice on this would be greatly appreciated.
Errors upon first change attempt:
2020-07-29 10:54:35:497 [asdf#asdf.com E6DD9F] ERROR
DefaultRestExceptionHandler.defaultErrorHandler:120 - Error invoking '/service/form/save'. Exception: org.springframework.transaction.TransactionSystemException. Message: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction.
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
Caused by: javax.persistence.RollbackException: Error while committing the transaction
Caused by: java.util.ConcurrentModificationException: null
Errors upon 2nd or more attempts:
2020-07-29 11:24:48:311 [asdf#asdf.com CD065A] ERROR DefaultRestExceptionHandler.defaultErrorHandler:120 - Error invoking '/service/form/save'. Exception: java.util.ConcurrentModificationException. Message: null.
java.util.ConcurrentModificationException: null

How can I confirm that Spring Transactions are working properly?

I working on an Spring 3.2 application running in OC4j. I have a number of methods annotated with Spring's #Transactional annotation as follows:
// in MyServiceImpl
#Transactional()
public void insertPaymentData(PaymentParams paymentParams) {
// call to MyDaoImpl which in turn calls a
// Spring JDBC Stored Procedure implementation
}
// in the Stored Procedure implementation
#Transactional(propagation = Propagation.MANDATORY)
public void insertPaymentData(PaymentParams paymentParams) {
// execute procedure here
}
In the logs for my local OC4J instance I see entries such as the following which make me think that Transactions are configured correctly:
[1.2.3.4-user123] 2019-03-20 17:36:14,805 DEBUG AbstractFallbackTransactionAttributeSource::getTransactionAttribute - Adding transactional method 'MyServiceImpl.insertPaymentData' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_1800; ''
[1.2.3.4-user123] 2019-03-20 17:36:14,809 DEBUG AbstractBeanFactory::doGetBean - Returning cached instance of singleton bean 'transactionManager'
[1.2.3.4-user123] 2019-03-20 17:36:14,812 DEBUG AbstractPlatformTransactionManager::getTransaction - Creating new transaction with name [my.app.service.payments.MyServiceImpl.insertPaymentData]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_1800; ''
[1.2.3.4-user123] 2019-03-20 17:36:14,821 DEBUG AbstractBeanFactory::doGetBean - Returning cached instance of singleton bean 'transactionManager'
[1.2.3.4-user123] 2019-03-20 17:36:14,822 DEBUG AbstractPlatformTransactionManager::handleExistingTransaction - Participating in existing transaction
[1.2.3.4-user123] 2019-03-20 17:36:14,822 DEBUG DataSourceUtils::doGetConnection - Fetching JDBC Connection from DataSource
[1.2.3.4-user123] 2019-03-20 17:36:14,823 DEBUG DataSourceUtils::doGetConnection - Registering transaction synchronization for JDBC Connection
[1.2.3.4-user123] 2019-03-20 17:38:42,550 DEBUG DataSourceUtils::doReleaseConnection - Returning JDBC Connection to DataSource
[1.2.3.4-user123] 2019-03-20 17:38:42,551 DEBUG AbstractPlatformTransactionManager::processCommit - Initiating transaction commit
Sometimes I see timeout and rollback messages there too.
However when I deploy to the development server provided by the ops department I do not see any messages like this in the logs, although the DEBUG level messages are displayed there too. I added in the following logging lines which I found somewhere on stack overflow:
logger.debug("Transaction name=" + TransactionSynchronizationManager.getCurrentTransactionName());
logger.debug("isActualTransactionActive=" + TransactionSynchronizationManager.isActualTransactionActive());
logger.debug("isSynchronizationActive=" + TransactionSynchronizationManager.isSynchronizationActive());
In the logs I now see things like this:
Transaction name=my.app.service.payments.MyServiceImpl.insertPaymentData
isActualTransactionActive=true
isSynchronizationActive=true
Are these values from TransactionSynchronizationManager telling me anything useful?
Is it telling me that transactions are working fine and to stop worrying?
I have the following in a Spring configuration file:
#Configuration
#EnableTransactionManagement
public class TransactionConfig {
#Bean
public JtaTransactionManager transactionManager() {
return new JtaTransactionManager();
}
}
And I have the following in a spring xml config file:
<tx:annotation-driven transaction-manager="transactionManager" />
Thanks!

Spring Boot + Atomikos: Exception thrown in a transactional JMS listener inside try-catch immediately causes rollback

I'm using Spring Boot 1.5.3 and Atomikos 4.0.6. I have a DefaultMessageListenerContainer setup to listen a JMS queue and handle incoming messages in a transaction using the Spring JTATransactionManager configured to use Atomikos. The message handler calls a transactional service that tries to process the message inside a try-catch-block and in case of exceptions calls other transactional methods for logging purposes. The idea is that the transaction should be rolled back only after everything is logged and the encountered RuntimeException is thrown from the catch-block.
#Transactional
public void handleMessage(UnmarshalledMessage message) {
try {
Thing thing = repository.find(message.getId());
...
}
catch (Exception e) {
// NoResultException translated into EmptyResultDataAccessException
logger.logUsingTransactions(e.getMessage());
throw e;
}
}
However, what happens that the transaction is rolled back immediately after it's originally thrown inside repository.find(). When attempting to read from the database inside the catch-block, an exception is thrown since the transaction has been marked as rollback only:
c.atomikos.jdbc.AtomikosSQLException - Transaction is marked for rollback only or has timed out
com.atomikos.datasource.xa.session.InvalidSessionHandleStateException: Transaction is marked for rollback only or has timed out
at com.atomikos.datasource.xa.session.NotInBranchStateHandler.checkEnlistBeforeUse(NotInBranchStateHandler.java:39)
at com.atomikos.datasource.xa.session.TransactionContext.checkEnlistBeforeUse(TransactionContext.java:70)
at com.atomikos.datasource.xa.session.SessionHandleState.notifyBeforeUse(SessionHandleState.java:160)
at com.atomikos.jdbc.AtomikosConnectionProxy.enlist(AtomikosConnectionProxy.java:207)
at com.atomikos.jdbc.AtomikosConnectionProxy.invoke(AtomikosConnectionProxy.java:122)
at com.sun.proxy.$Proxy129.prepareStatement(Unknown Source)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.prepareStatement(DatabaseAccessor.java:1565)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.prepareStatement(DatabaseAccessor.java:1514)
at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.prepareStatement(DatabaseCall.java:778)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:621)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:560)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2055)
at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:258)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectOneRow(DatasourceCallQueryMechanism.java:714)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRowFromTable(ExpressionQueryMechanism.java:2803)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRow(ExpressionQueryMechanism.java:2756)
at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:555)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1175)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:904)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1134)
at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:441)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1222)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1857)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1839)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1790)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.executeQuery(EntityManagerImpl.java:911)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.findInternal(EntityManagerImpl.java:854)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:730)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:599)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
I'd like to know what is causing this behavior and how to resolve the issue. Note that this setup has been working correctly when run in Weblogic. For additional information, here is a transaction trace log when the exception is first encountered inside the repository method.
DEBUG o.s.t.jta.JtaTransactionManager - Initiating transaction commit
DEBUG o.s.t.jta.JtaTransactionManager - Creating new transaction with name [myMessageListenerContainer]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG o.s.t.jta.JtaTransactionManager - Participating in existing transaction
TRACE o.s.t.i.TransactionInterceptor - Getting transaction for [my.transactional.messagehandler.handleMessage]
DEBUG o.s.t.jta.JtaTransactionManager - Participating in existing transaction
TRACE o.s.t.i.TransactionInterceptor - Getting transaction for [my.repository.class.method]
TRACE o.s.t.i.TransactionInterceptor - Completing transaction for [my.repository.class.method] after exception: org.springframework.dao.EmptyResultDataAccessException: ProcessableMessage with id 443e73e7-0905-416b-9e03-4aaa2bbf09fb; nested exception is javax.persistence.NoResultException: ProcessableMessage with id [message-id]
TRACE o.s.t.i.RuleBasedTransactionAttribute - Applying rules to determine whether transaction should rollback on org.springframework.dao.EmptyResultDataAccessException: ProcessableMessage with id 443e73e7-0905-416b-9e03-4aaa2bbf09fb; nested exception is javax.persistence.NoResultException: ProcessableMessage with id [message-id]
TRACE o.s.t.i.RuleBasedTransactionAttribute - Winning rollback rule is: null
TRACE o.s.t.i.RuleBasedTransactionAttribute - No relevant rollback rule found: applying default rules
DEBUG o.s.t.jta.JtaTransactionManager - Participating transaction failed - marking existing transaction as rollback-only
DEBUG o.s.t.jta.JtaTransactionManager - Setting JTA transaction rollback-only
EDIT:
I am using JPA and the NoResultException is initially thrown in a following way:
public static <T> T mandatoryFind(EntityManager em, Class<T> type, Object id) throws NoResultException {
T found = em.find(type, id);
if (found == null) {
throw new NoResultException(type.getSimpleName() +" with id "+ id);
}
return found;
}
Which in turn is called from a class annotated with #Transactional(noRollbackFor = NoResultException.class). The exception is raised in a fairly normal use case - what I'm troubled with is why the transaction is rolled back before I can handle the exception?
It sounds like you do use JPA under the hood (based on your debug logs).
This is a typical behaviour then you do query a single result.
NoResultException:
Thrown by the persistence provider when Query.getSingleResult() or TypedQuery.getSingleResult()is executed on a query and there is no result to return. This exception will not cause the current transaction, if one is active, to be marked for rollback.
In order to avoid that behaviour you do query result as a List.

Transaction management in Spring Boot and Spring data jpa

Altough transaction management works Spring Data Repositories create their own transaction and suspend the active one.
I have following Spring application:
Application class:
#SpringBootApplication
#EnableTransactionManagement
public class SpringbootTxApplication {... }
Service class:
#Service
public class EntityService {
...
public void addEntityWithoutTransaction(MyEntity myEntity) {
log.debug("addEntityWithoutTransaction start");
myEntityRepository.save(myEntity);
log.debug("addEntityWithoutTransaction end");
}
#Transactional
public void addEntityTransaction(MyEntity myEntity) {
log.debug("addEntityTransaction start");
myEntityRepository.save(myEntity);
log.debug("addEntityTransaction end");
}
}
While exeucting my EntityServiceTest which executes each method once and having spring transaction log in trace, I get following output:
... TRACE ... o.s.t.i.TransactionInterceptor : Getting transaction for [de.miwoe.service.EntityService.addEntityTransaction]
... DEBUG ... de.miwoe.service.EntityService : addEntityTransaction start
... TRACE ... o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... TRACE ... o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... DEBUG ... de.miwoe.service.EntityService : addEntityTransaction end
... TRACE ... o.s.t.i.TransactionInterceptor : Completing transaction for [de.miwoe.service.EntityService.addEntityTransaction]
And
... DEBUG ... de.miwoe.service.EntityService : addEntityWithoutTransaction start
... TRACE ... o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... TRACE ... o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... DEBUG ... de.miwoe.service.EntityService : addEntityWithoutTransaction end
Obviously according to the log, the #Transactional-Annotation is working in addEntityTransaction, but the repository still creates its own transaction.
Why? Official docs (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions) describe it should not begin a new one if it already exists.
(Sometimes, Convention over Configuration seems more like Irritation over Convention over Configuration....)
Am I missing something?
(Complete code is also available here: https://github.com/miwoe/springboot-tx)
Your question (main point):
... TRACE ... o.s.t.i.TransactionInterceptor : Getting transaction for [de.miwoe.service.EntityService.addEntityTransaction]
... DEBUG ... de.miwoe.service.EntityService : addEntityTransaction start
... TRACE ... o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... TRACE ... o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
... DEBUG ... de.miwoe.service.EntityService : addEntityTransaction end
... TRACE ... o.s.t.i.TransactionInterceptor : Completing transaction for [de.miwoe.service.EntityService.addEntityTransaction]
Obviously according to the log, the #Transactional-Annotation is
working in addEntityTransaction, but the repository still creates its
own transaction.
Answer:
You work inside one physical transaction.
When start call service spring starts new transaction and set TransactionStatus.isNewTransaction = true , when you
call dao method spring check that method also transactional and create the second transaction for dao , BUT set for second transaction TransactionStatus.isNewTransaction = false .If you set required_new for dao method/class only in this case it be marked as TransactionStatus.isNewTransaction = true. At commit time only first transaction (physical ) is commited. If you mark the second transaction it will be ignored at commit time, and the first transaction is committed.
AbstractPlatformTransactionManager
if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
doCommit(status);
}
You can check in debug mode.
Main point : you work inside one transaction that might be marked as commit or rollback.In TRACE you see, details about, what spring transaction does, and for you,it doesn't matter how many logical transactions creates inside on physical transaction. You have guaranty, for a transaction with propagation level REQUIRED ,that if you call the transactional method from another transaction method only one physical transaction is created and one is committed or rollbacked.
PROPAGATION_REQUIRED
When the propagation setting is PROPAGATION_REQUIRED, a logical
transaction scope is created for each method upon which the setting is
applied. Each such logical transaction scope can determine
rollback-only status individually, with an outer transaction scope
being logically independent from the inner transaction scope. Of
course, in case of standard PROPAGATION_REQUIRED behavior, all these
scopes will be mapped to the same physical transaction. So a
rollback-only marker set in the inner transaction scope does affect
the outer transaction’s chance to actually commit (as you would expect
it to).
The repository methods are #Tranactional because you're leveraging the JpaRepository interface and allowing the framework to implement that for you.
It chooses SimpleJpaRepository by default which uses #Transactional. Take a look at the source and you'll see where it's being used.

Spring Transactions - Prevent rollback after unchecked exceptions (RuntimeException)

I can't manage to prevent a transaction from rolling back after a RuntimeException.
My env is Spring 4.1 + Hibernate 3.6 + JTA (WebSphereUowTransactionManager) running on Websphere 8.0.
"doStuff" case: works
First off, a simple case that behaves as expected. Since I catch the RuntimeException, the transaction commits and the new resource is created successfully.
#Service("fooService")
public class FooServiceImpl implements IFooService {
#Transactional
#Override
public void doStuff(Resource res){
authService.createResource(res, "ADMIN");
try {
throw new RuntimeException("SOMETHING");
} catch (RuntimeException e) {
e.printStackTrace();
}
}
"doStuff2" case: works
The next one is OK as well. I declare the noRollbackFor and it let's the transaction commit:
#Transactional(noRollbackFor=RuntimeException.class)
#Override
public void doStuff2(Resource res){
authService.createResource(res, "ADMIN");
throw new RuntimeException("SOMETHING");
}
"doStuff12" case: does NOT work
And finally the problematic one. The difference is that in this case the exception is raised by the second call to authService.createResource. FYI, authService.createResource is only marked as #Transactional, so the default Propagation configuration applies and it should be joining the calling service's transaction.
#Transactional(noRollbackFor=RuntimeException.class)
#Override
public void doStuff12(Resource res){
authService.createResource(res, "ADMIN");
try{
res.setName("EXISTING-RESOURCE");
authService.createResource(res, "ADMIN");
}catch(RuntimeException e){
e.printStackTrace();
}
}
Despite catching the RuntimeException and declaring the noRollbackFor attribute the transaction always rolls back. Any explanation??
Log trace info:
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '',+com.myorg.webapps.exception.ElementoYaExistente
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=false
org.springframework.transaction.support.TransactionSynchronizationManager TRACE - Initializing transaction synchronization
org.springframework.transaction.interceptor.TransactionInterceptor TRACE - Getting transaction for [com.myorg.test.service.impl.FooServiceImpl.doStuff12]
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=true
org.springframework.transaction.interceptor.TransactionInterceptor TRACE - Getting transaction for [com.myorg.authmgr.service.impl.AuthorizationServiceImpl.createResource]
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Returned from WebSphere UOW action: type=1, join=true
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=true
org.springframework.transaction.interceptor.TransactionInterceptor TRACE - Getting transaction for [com.myorg.authmgr.service.impl.AuthorizationServiceImpl.createResource]
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute TRACE - Applying rules to determine whether transaction should rollback on java.lang.Runtime: Couldn't create the resource, it already exists: EXISTING-RESOURCE
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute TRACE - Winning rollback rule is: null
org.springframework.transaction.interceptor.RuleBasedTransactionAttribute TRACE - No relevant rollback rule found: applying default rules
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Returned from WebSphere UOW action: type=1, join=true
org.springframework.transaction.jta.WebSphereUowTransactionManager TRACE - Triggering beforeCommit synchronization
org.springframework.transaction.jta.WebSphereUowTransactionManager TRACE - Triggering beforeCompletion synchronization
org.springframework.transaction.support.TransactionSynchronizationManager TRACE - Clearing transaction synchronization
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Returned from WebSphere UOW action: type=1, join=false
As far as I know, as soon as a runtime exception is thrown from a transactional method and is intercepted by the transaction interceptor, the transaction is marked as rollback only. Even if this transactional method is called from another transactional method.
This makes sense to me: if the inner method can't recover from an exception, it can't recover, and an outer method shouldn't do as if nothing happened.
If you're expecting the transaction not to rollback, you could
make the inner method non-transactional
configure the inner method not to rollback on this exception
have two inner methods:
one that is transactional, and is intended to be called when there is no transaction yet, and which simply delegates to the second one
one which is not transactional, and is intended to be called as part of an already existing transaction

Resources