Activiti + spring + transaction + rollback - spring

I want to test the integration of Spring and Activiti, then I stuck with confusing problem. I have a workflow with 2 service task (using jpa repository saveAndFlush method to update database) A and B
In the service A, I actively throw a new Exception , then the transaction rollbacks, and the flow stops. Well, it's okay.
However, how can I rollback the service A only and the flow continue to service B?
Because if service A throws Exception, the flow will be stopped, and if Exception is caught ( then the flow continues), service A will not rollback.
I use JPA Repository to automatically handle transaction, so change to manual mode will take a lot of efforts now.

Probably you need a new transaction for every service in the flow and catch all exception.

Put a layer between your service tasks A,B and your process, let's make its name TransactionService. This service should trigger your service methods. Also those service methods should use new transactions for their operations(you can use #Transactional annotation). In TransactionService don't do anything, just trigger them and wrap them in try catch blocks.
As a result of them you can catch the exception and make it flow to the next task and doesn't care about rollback because after an exception it will be rolled back automatically.

Related

Spring Transaction - Do not rollback for error under specific method

I have a Spring Boot application in which a service is responsible to create a Business Entity. For simplicity, let's consider:
create(Object toCreate) {
validationService.validate(toCreate);
Object created = repository.save(toCreate);
notificationService.notify(created);
}
Business has changed and now I would like the creation to not fail if notification fails.
I therefore wrapped the notify() method in a try-catch block that only logs the error (which is a RuntimeException).
However when tested, a transaction rollback error was thrown, saying the connection was closed. I do not want any rollback, especially since the NotificationService does not modify the database.
How can I tell Spring that any exception happening in the NotificationService is fine and does not require a rollback? I tried annotating the class/method with #Transactional(propagation=NEVER) but got existing transaction found for transaction marked with propagation 'never'
Perhaps refactoring your code would help better than the introduction of more complex transaction handling.
Assuming your #Transactional is on the create() method, we can see that you have:
Pre-persistence business logic
Persistence logic
Post-persistence business logic
It depends on your use-case, but I would not expect pts. 1 & 3 to contain persistence logic. If that is the case, you could extract your persistence logic in its own service that would itself be a transaction, not the parent.
If you have the need for a transaction in those steps, you could also extract them in their own transaction.
Other leads might be:
The default rollback behavior is for runtime unchecked exceptions. You could use checked exceptions to avoid the rollback.
If your notification is separate from persistence and you do not care about the transaction, you could make it an asynchronous call (e.g. with #Async). It would be scheduled outside of the transaction in its own context.
You can use the option norollbackfor of #Transactional so you have to specify an exception class not the service and when an error occurs in notifications try to throw a specifc error which would not cause a rollback.

how java manage jdbc connections

I have an spring advice method which logs the exception after a method (in DAO layer) throws an exception. The DB query are handled at DAO classes.
while running the code my service method (S1), which interns call DAO layer method (D1) to execute query.
test case: DB is up and code execute normally. in second run, meanwhile DB is down, and calls doesn't reach to DAO layer and exception throws (Connect excpetion) at service layer (S1) itself; hence advise not able to log the excpetion because calls is not reached to DAO.
how the jdbc connections are managed by server (tomcat)?

Transaction propagation between services in spring

I have two services both are transactional with propagation REQUIRED. Service 2 is injected in service 1.Now method A in service 1 calls method B of service 2. Now I am invoking method A from client.My question is whether this invocation will
Create 1 transaction in which is created by Method A and method B will run in same transaction
Or
Create 2 transactions one for method A and other when A is calling B.
In my project services are transactional and for performing compound operations we have injected services inside other services.
From REQUIRED java-doc:
Support a current transaction, create a new one if none exists.
In your case - your variant is 1.
Note: You can control the creation of your transactions by enabling debug logging for org.springframework.orm.jpa.
More info from official doc.

XA transactions and message bus

In our new project we would like to achieve transactions that involve jpa (mysql) and a message bus (rabbitmq)
We started building our infrastructure with spring data using mysql and rabbitmq (via spring amqp module). Since rabbitMq is not XA-transactional we configured the neo4j chainedTransactionManager as our main transactionManager. This manager takes as argument the jpa txManager and the rabbitTransactionManager.
Now, I do get the ability to annotate a service with #Transacitonal and use both the jpa and rabbit inside it. If I throw an exception within the service then none of the actions actually occur.
Here are my questions:
Is this configuration really gives me an atomic transaction?
I've heard that the chained tx manager is not using a 2 phase commit but a "best effort", is this best effort less reliable? if so how?
What the ChainedTransactionManager does is basically start and commit transactions in reverse order. So if you have a JpaTransactionManager and a RabbitTransactionManager and configured it like so.
#Bean
public PlatformTransactionManager transactionManager() {
return new ChainedTransactionManager(rabbitTransactionManager(), jpaTransactionManager());
}
Now if tha JPA commit succeeds but your commit to rabbitMQ fails your database changes will still be persisted as those are already committed.
To answer your first question it doesn't give you a real atomic transaction, everything that has been committed prior to the occurence of the Exception (on committing) will remain committed.
See http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/transaction/ChainedTransactionManager.html

Transaction not rolling back

I have mybatis 3.0.4 with mybatis-spring integration 1.0.1 deployed within Fuse (OSGi). I've created a basic database within SQLServer 2008. In Spring I've configured a TransactionAwareDataSourceProxy data source and a DataSourceTransactionManager transaction manager.
Now I've created my own bundle to be deployed within Fuse which inserts some rows into the database. I've told the bundle to use the configured data source and transaction manager. The method which carries out the logic looks like this:
#Transactional(propagation=Propagation.REQUIRED)
public void go(RecsCashContext context) throws ActionException {
When this method throws an exception I can follow Spring through seeing the expected behaviour triggered. This leads me to Springs JtaTransactionManager and doRollBack(..).
So everything looks promising, except that when I look at the database, sure enough it's in an unstable state as previous inserts have not been roll back.
I'm at a loss on this one and I'm struggling to find any information online. Any thoughts?
What kind of exception is being thrown? Unless you tell Spring to explicitly rollback when a particular exception is thrown, it will proceed. By default, Spring's transaction handling only rolls back when an unchecked exception (e.g. RuntimeException) is thrown. In your case, if you're expecting the rollback to occur when ActionException occurs, you're out of luck unless you make the following modification:
#Transactional(rollbackFor={ActionException.class})
public void go(RecsCashContext context) throws ActionException {
More details are in here, specifically in section 10.5.6.1, #Transactional settings
As it turns out Fuse (servicemix) already exposes a transaction manager via an OSGi service within bundle org.apache.aries.transaction.manager_0.2.0.incubating [49]. As a result when I was looking up the transaction manager service, the one exposed by bundle 49 got picked up first.
This was resolved by clearly specifying the transaction manager I was interested in. At the moment I am doing this using the bean-name propery:
<osgi:reference id="transactionManager" bean-name="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
Though this could also be done by using a filter, but preferably we'll just make use of the transaction manager service that's already being expose as opposed to providing our own.

Resources