use aspectj to retry deadlocked transactions in spring boot - spring

I created a deadlock situation by having 2 functions lock 2 rows in a mysql table in opposite orders. I have #Transactional on both functions. I also have an aspectj aspect on both functions that retries the failed one at most 2 more times.
After the deadlock, one thread succeeds and one fails. The failed one retries. So far so good. However, there are 2 problems after this point.
When the failed function was retried a second time, it reads the 2 rows again. However, the value for the first one is old and the second one is new.
At the end, the transaction fails because the transaction was already marked for rollback. So the #Transactional proxy is around the retry proxy. Is there a way to reverse the order? I tried to have the retry proxy inherit Ordered and set the order to Ordered.HIGHEST_VALUE and Ordered.LOWEST_VALUE but neither worked.

I tried spring retry and it worked like a charm. Still looking into how it does it magic though.
I basically did this:
add dependency on org.springframework.retry spring-retry
add #EnableRetry to application
add #Retryable(maxAttempts = 3, backoff = #Backoff(delay = 2000)) above
#Transactional annotated functions.

This one has the more direct answer:
Intercepting #Transactional After Optimistic Lock for Asynchronous Calls in Restful App
Just added #Order(1) below the aspect.
Turned out the key was to use 1 as the order. I tried the Ordered interface again just like in the problem description. This time using 1 and it worked just the same as the Order annotation is just a shortcut to the interface.

Related

Understanding transactions in Spring Test

I have a little bit trouble with Integration Test and the transactions.
I have a Rest Service System. Behind all I have a JPA-Repository, with a Postgres database. Now to test them I build JunitTest where I made the calls on the System. The test loads the web-context and an other xy-context where I have the configuration of security and database connections. On the test method I have the #Transactional annotation.
The test makes 2 requests (This is only one example I have more of similar scenarios on other Object):
insert a new user
on this user create a Group and after bind this to the user
The test makes the first call, and returns me a id where I use to perform the second call.
The second call take the id and make the post and there I have several problems.
Details of the second call:
Test make a post on a controller
Controller takes the request and forward it to the Service
Service method (with #Transactional) take the request and do:
a research to find the inserted user
insert a group object
update the user with the groupId (generated on point 2)
Now one of the problems I had, it was a AccessDeniedException on point 3.1, because I have also ACL, and I have to check if there are enough permissions.
One of the things that I tried to do is to set:
#Transactional(propagation=Propagation.REQUIRES_NEW)
on the Service Method.
What I get after is the result that the AccessDeniedException was disappeared but the research at 3.1 gives me empty result (the research is ok, because on other scenario I have correct results), but is strange because the first post was ok, and how I understand Spring handles the #Transactions and "commits" to database so that a commit is performed when a transaction is closed. This brings me to an other idea to try: remove the #Transaction annotation on the test, but when i made this, then the database has all the data of this scenario until the end of the tests session (If you have a lot of test this is not desirable), and this is not a very good thing.
Now I wrote a little bit where are my doubts, and problems without posting a lot of code and of privacy problems, but on request I can post little pieces of codes.
It's also probable that the approach is incorrect.
The questions are:
-how can I make this service work?
-It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
-It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
Txs a lot.
To make test I use mockMvc to make the request and some annotation on the class:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(locations = { ..... })
#Transactional
public class tests {
#Test
public void aTest(){
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter(new DelegatingFilterProxy("springSecurityFilterChain", webApplicationContext), "/*")
.build();
mockMvc.perform(post(.....))
}
}
To answer your question:
It's the correct way to set #Transactional on the test? (eventually with a Rollback?)
No really, but you can. Because you are doing two requests, the second depends on the first, and http request will not remember your transaction, if you insist to do it, you need flush your session between requests.
It's the correct way to set (propagation=Propagation.REQUIRES_NEW)?
It depends. REQUIRES_NEW means it will start new transaction, the influence is that everything in the existing transaction will be invisible in the new transaction, because the old one is not commited yet! if this server is the entry point of the transaction, it makes no difference, but be aware of the visibility problem.
how can I make this service work?
OK, forget what my answers of the previous questions. If I have to write the test, I will do it this way:
The test is not transactional. If you are doing integration test, you don't need to rollback single tests. If you wanna rollback the commit, then you are having wrong task case, you should have two test cases insert user and update group.
3 parts of the test
Send request to insert user and get the ID (single transaction)
Send request to update group(another transaction)
Send request to fetch the user and do the checks.
Hope this can help you.

Spring Declarative transaction management with hibernate using #Transactional

My requirement is to save data in 5 tables through 5 methods .
These 5 methods are wrapped under single parent method which is annotated with #Transactional.
Am calling this parent method 100 times in a loop.
Constraints are
Transaction has to be rolled back even if one method fails in one iteration.(i.e 5 methods has to be saved without exception) and the flow should continue for next iteration.
One iteration fail should not rollback all the other iterations. I.,e In 100 iterations if 5th iteration fails and all the other iterations are succeeded, then all the 99 iteration's operations should get committed.
It is OK if transaction is committed after successfully executing all the 5 methods in one iteration.
Issue is
If, 5th iteration is failed, then in next iteration, old values are showing in the entity.
I have used session.clear() method in catch block to avoid that. is that correct? But the issue is,
even after successful insertion of five methods in next iteration, the transaction is getting rolled-back. And all the previous 4 iteration's data state in session is getting cleared.
am using Spring 3.2, Hibernate3, HibernateTransactionManager
I forgot to write the caller method and calling method in different beans. Hence it is getting rolled back. Spring Transaction uses AOP. A proxy is created for the methods which are annotated with #Transactional. This bean method should be called from another bean, which I got form the Spring documentation
You want your iterations succeed or fail independently one from another. You want a failure in any of the 5 steps of the individual iteration to fail entire iteration and to roll back the corresponding transaction.
It is clear that you want to have transaction boundary at the level of the service call that corresponds to a single iteration. Now, the rule of the thumb is to allocate a Hibernate session per transaction. So, a Hibernate session should be created at the beginning of each iteration and be disposed of at the end. That would prevent random junk, like entites that failed to be persisted to the database in the previous trnsactions, from showing up in the Hibernate session.
Hope this helps.
Have a look into propagation levels of spring transactions here and choose whatever best suits your requirements. An example which does what you need is as follow (you may mark myService as #Transactional as well) but you might like to have a look at other levels.
public void myService() {
// call myTaskCaller as many times as you like
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void myTaskCaller() {
task1();
task2();
task3();
task4();
task5();
}
private void task1(){}
private void task2(){}
private void task3(){}
private void task4(){}
private void task5(){}

Spring and JUnit, the difference of annotating classes and methods with #Transaction?

I would like to understand that if I annotate my junit class with #Transactional, Spring will create only one transaction which will be shared among my #Test methods and rolled back at the end. Whereas if instead I mark each single #Test with #Transactional, a new transaction will be created and rolled back on a #Test basis. I didn't quite find the expected behaviour in the official documentation (link).
Putting #Transactional on a class level is equivalent to putting it on each of the test methods.
I don't think there is an easy way of achieving your first scenario, ie, a single transaction for all the tests. I am not sure it would make much sense anyway since tests will be executed in a random order so you cannot rely on seeing each others modifications. Of course you can always explicitly call your methods from a single uber-test with a single transaction.
#Transactional at JUnit test case class level will start new transaction before each test method and roll it back afterwards.
You cannot easily start new transaction at the beginning of test class and keep it open for the whole class, at least Spring is not supporting this. Your first workaround would be to use #BeforeClass/#AfterClass pair, but they must be static thus you don't have access to transactional manager.
But first ask yourself a question, why do you want to do this? Sounds like one test depends on the output or database side effects of the other. This is a big anti-pattern in testing, not to mention JUnit does not guarantee the order in which test methods are executed. Maybe you just need a database setup before each test case? #Before and #After are executed within the context of Spring transaction, so you can use them there.

spring scope for transaction

I'm a new Spring user.
I have a question about scope and transaction.
For example, there's a service:
<bean id="bankInDaoService" class="service.dao.impl.UserDaoServiceImpl">
Let's say there are 2 people who want to bank-in at the same time.
And I already put #Transactional above for Hibernate transaction the method for bank-in purpose.
My questions are:
Since default Spring scope is singleton. Will these 2 people share the same values. (person 1 bank-in 500, person 2 bank-in 500)?
Will the #Transactional be effective? I mean let the first person finishes bank-in, and then person 2.
I'll be really thankful for your help.
You have wrongly understood the useage of #Transactional annotation.
#Transactional annotation is used in case where you want to get all or none of your transactions to be successful. If any of the transaction fails then other successful transaction will be rolled back. It is not for synchronisation.
If you have registration page where you take input for 10 fields and 5 are for table user and 5 are for table company and you are inseting both records from a single service function. At that time you should use #Transactional annotation. If insertion is successful in user table and fails in company table then the user table record will be rolled back.
Hope this helps you. Cheers.
You are correct that by default Spring beans are singletons. But this won't be a problem unless your implementation modifies some internal state on each invocation (which would be rather odd - typically a service method will just work with the parameters it's been given).
As I just alluded to, each service method invocation will have its own parameters; i.e.:
deposit(person1_ID, 500)
deposit(person2_ID, 750)
As you've said "at the same time" we can safely assume we have a multi-threaded server that is handling both these people simultaneously, one per thread. Method parameters are placed on the stack for any given thread - so as far as your service is concerned, there is absolutely no connection/chance of corruption between the two people's deposits.
Now turning to the #Transactional annotation: Spring uses "aspects" to implement this behaviour, and again these will be applied separately to each thread of execution, and are independent.
If you're looking for #Transactional to enforce some kind of ordering (for example, you want person2 to withdraw the exact amount person1 deposited) then you need to write a new method that performs both operations in sequence within the one #Transactional scope.

Spring Bean Hangs on Method with #Transactional

Just a little background , I'm a new developer who has recently taken over a major project after the senior developer left the company before I could develop a full understanding of how he structured this. I'll try to explain my issue the best I can.
This application creates several MessageListner threads to read objects from JMS queues. Once the object is received the data is manipulated based on some business logic and then mapped to a persistence object to be saved to an oracle database using a hibernate EntityManager.
Up until a few weeks ago there hasn't been any major issues with this configuration in the last year or so since I joined the project. But for one of the queues (the issue is isolated to this particular queue), the spring managed bean that processes the received object hangs at the method below. My debugging has led me to conclude that it has completed everything within the method but hangs upon completion. After weeks of trying to resolve this I'm at end of my rope with this issue. Any help with this would be greatly appreciated.
Since each MessageListner gets its own processor, this hanging method only affects the incoming data on one queue.
#Transactional(propagation = Propagation.REQUIRES_NEW , timeout = 180)
public void update(UserRelatedData userData, User user,Company company,...)
{
...
....
//business logic performed on user object
....
......
entityMgr.persist(user);
//business logic performed on userData object
...
....
entityMgr.persist(userData);
...
....
entityMgr.flush();
}
I inserted debug statements just to walk through the method and it completes everything including entityMgr.flush.().
REQUIRES_NEW may hang in test context because the transaction manager used in unit testing doesn't support nested transactions...
From the Javadoc of JpaTransactionManager:
* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
* The {#link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults
* to {#code false} though, since nested transactions will just apply to the JDBC
* Connection, not to the JPA EntityManager and its cached entity objects and related
* context. You can manually set the flag to {#code true} if you want to use nested
* transactions for JDBC access code which participates in JPA transactions (provided
* that your JDBC driver supports Savepoints). <i>Note that JPA itself does not support
* nested transactions! Hence, do not expect JPA access code to semantically
* participate in a nested transaction.</i>
So clearly if you don't call (#Java config) or set the equivalent flag in your XML config:
txManager.setNestedTransactionAllowed(true);
or if your driver doesn't support Savepoints, it's "normal" to get problem with REQUIRES_NEW...
(Some may prefer an exception "nested transactions not supported")
This kind of problems can show up when underlying database has locks from uncommitted changes.
What I would suspect is some other code made inserts/deletes on userData table(s) outside transaction or in a transaction which takes very long time to execute since it's a batch job or similar. You should analyze all the code referring to these tables and look for missing #Transactional.
Beside this answer, you may also check for the isolation level of your transaction — perhaps it's too restrictive.
Does the update() method hang forever, or does it throw an exception when the timeout elapses?
Unfortunately I have the same problem with Propagation.REQUIRES_NEW. Removing it resolves the problem. The debugger shows me that the commit method is hanging (invoked from #Transactional aspect implementation).
The problem appears only in the test spring context, when the application is deployed to the application server it works fine.

Resources