Timeout Exception error when making a Transactional operation with Spring - java

I am involved in a new project and I was assigned to investigate an error that is happening when apparently a transaction(or more than one) to the database in being performed. We are using Java for the backend(Spring framework), MyBatis for mapping objects and Websphere Liberty as server, the problem comes in some methods that are marked as #Transactional, this is the declaration:
#Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED,isolation=Isolation.READ_UNCOMMITTED)
Inside the method there are some executions to the database and apparently in some cases throws a TimeoutException and makes Rollback of operation, I guess concurrent calls make this(I am not sure) this is the error image we got:
I am new in transactions and I donĀ“t know if the parameters declared could affect in the performance, what can cause a TimeoutException as this?
I am lost, I would be grateful with any help.
Thank you.

Related

Rollback Spring Transaction after network failure

I'm working on rather simple RESTful service based on SpringBoot. I'm using Ebean and SpringData. All my REST methods are annotated with #Transactional:
#Transactional
#PostMapping
public Entity createEntity(...) {
// some code
}
The problem I'm facing is that if there is a network issue but this method executes without an exception, the transaction will still get committed. For example, the client might send the data, my code creates the record but then the server can't send a response back to the client. In this case, I'd want the transaction to rollback but I didn't find a way of doing that.
Is it even possible to rollback the transaction in this case? Maybe there is a Spring platform limitation I'm overlooking.
Thanks
EDIT: To answer the replies below and specify the question further: It's easy enough to rollback the transaction. The tricky part is to run any code in response to the network failure. I was hoping that I can configure Spring to do it for me. Like "wait until you sent the last byte and then rollback or commit the transaction". My current code will commit the transaction as soon as the createEntity() method has finished.
This is not Spring framework's limitation. Once the method is executed successfully, it is NOT spring framework's #Transactional responsibility to roll it back.
The best you could do is to have an ExceptionHandler. See this answer for a better perspective: https://stackoverflow.com/a/45034574/945214
The other thing you could do is to improve the performance of the whole HTTP request topology, so that the probability of the such potential failure(s) reduces (as the touch time decreases). See my writeup on app performance at: https://www.linkedin.com/pulse/improving-website-performance-kshitiz-garg/
If you can find out when you need to rollback (checking a return status/...), you can just throw your own Exception.
Watchout as it only rollbacks for unchecked Exception (otherwise, you'll need to add rollbackFor=Exception.class on your #Transactional if you want it to rollback for any exception).
See :
https://www.catalysts.cc/wissenswertes/spring-transactional-rollback-on-checked-exceptions/
Annotation #Transactional. How to rollback?
You can rollback Transaction without throwing an exception using:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Spring #Transactional read-only mode rollback behaviour

I have some service layer method with #Transactional(readOnly=true) and this method causes some RuntimeException quite often (let's say it is some NotFoundException exception).
I'm using ORM Hibernate also for the DB interaction process.
Is it legal pattern to do so?
What is the default behaviour in this case in sense of "roll-back" behaviour? Can it influence somehow badly on connections's state or lead to any problems?
It isn't something like "why not try it by your self?". I have a suspicion that this could lead to the Transaction rolled back because it has been marked as rollback-only error in the same method after some number of exceptions. This could be very specific JDBC PostgreSQL driver error. That is why I'm wondering about this design in general: is it something legal or illegal to do so?
So as far as I understand, you are worried about the roll-back. In this case a readOnly is a select statement and usually there is nothing to roll-back from a read. The only place where this is handy is when you read under a lock and when the transaction finishes you release that lock.
AFAIK readOnly will set the flushmode to FlushMode.NEVER and that is good and bad at the same time. Good, because there will no dirty checking, as described here. Bad because if you call a read/write transaction within a readOnly transaction, the transaction will silently fail to commit because the session is not flushed. This is easily testable btw - and I hope things have not changed since I've tried this.
Then there is the pool of connections. I know that C3P0's default policy is to rollback any uncommitted work. The flag to control this is autoCommitOnClose.
Then there is this link about readOnly and postgres - which I have not worked with and can't really tell my opinion on.
Now to your point about Transaction rolled back because it has been marked as rollback-only. For a readOnly transaction there might be nothing to roll-back as I said before, so this really depends on how you chain your #Transactional methods IMO.

how to stop specific exceptions from being logged onto the server

I am new to JBoss. As part of My Application I am using JBoss.We are also using EJB's as a part of the project also. A exception like StaleObjectStateException is raised . So , the EJB uses this exception to rollback a transaction. So, Please tell me how to stop StaleObjectStateException from being logged.Log4j is used here.
StaleObjectStateException being a runtime exception, shouldn't be caught in normal cases
But the only way for you to stop it from coming to logs, is to catch the exception in your code and eat up.
However, IMHO it should be of prime importance to figure out why you are getting this exception.
org.hibernate.StaleObjectStateException is a Hibernate exception that usually indicates that some other thread of control has updated the state of your entity bean in the database.
You must catch it before it is thrown from an EJB and deal with it somehow.
Any RuntimeException that is thrown from an EJB call automatically results in transaction rollback.
You should also read the javadoc for org.hibernate.StaleStateException to ensure that some of the other scenarios it describes do not apply to you.

Synchronizing spring transaction

We use Spring and Hibernate in our project and has a layered Architechture. Controller -> Service -> Manager -> Dao. Transactions start in the Manager layer. A method in the service layer which updates an object in the db is called by many threads and this is causing to throw a stale object expection. So I made this method Synchronized and still see the stale object exception thrown. What am I doing wrong here? Any better way to handle this case?
Thanks for the help in advance.
The stale object exception is thrown when an entity has been modified between the time it was read and the time it's updated. This can happen inside a single transaction, but may also happen when you read an object in a transaction, modify it (in the controller layer, for example), then start another transaction and merge/update it (in this case, minutes or hours can separate the read and the update).
The exception is thrown to help you avoid conflicts between users.
If you don't care about conflicts (i.e. the last update always wins and replaces what the previous ones have written), then don't use optimistic locking. If you're concerned about conflicts, then StaleObjectExceptions will happen, and you should popup a meaningful message to the end user, asking him to reload the data and try to modify it again. There's no way to avoid them. You must just be optimistic and hope that they won't happen often.
Note that your synchronized trick will work only if
the exception happens only when reading and writing in the same transaction
updates to the entity are only made by this service
your application is not clustered.
It might also reduce the throughput dramatically, because you forbid any concurrent updates, regardless of which entities are updated by the concurrent transactions. It's like if you locked the whole table for the duration of the whole transaction.
My guess is that you would need to configure optimistic locking on the Hibernate side.

Dealing with RollbackException in Java

Is there any way to "replay" transaction?
I mean, sometimes I get RollbackException and rollback the transaction. Can I then "clone" the transaction and try again, or once rollback is called, transaction is lost?
I really need the changes, and really don't want to trace every change for rerunning later...
thanks,
udi
Why do you get the exception in the first place ? This seems to me to be the crux of the matter.
Are you relying on optimistic writing ? If so, then you'll have to wrap your database writes in some form of loop, incorporating (perhaps) a backoff and a number of retries. You can't do this automatically, unfortunately (unless you investigate some form of AOP solution wrapping your database writes with a retry strategy ?)
That depends where that transaction comes from. In Java/JDBC, a transaction is tied to a connection. You start one by setting setAutoCommit() to false (otherwise, every statement becomes its own little transaction).
There is nothing preventing you from reusing the connection after a transaction failed (i.e. you called rollback).
Things get more tricky when you use Spring. Spring wraps your methods in a transaction handler and this handler tries to guess what it should do with the current transaction from the exceptions that get thrown in the method. The next question is: Which wrapper created the current transaction? I just had a case where I would call a method foo() which would in turn call bar(), both #Transactional.
I wanted to catch errors from bar() in foo() and save them into the DB. That didn't work because the transaction was created for foo() (so I was still in a transaction which Spring thought broken by the exception in bar()) and it wouldn't let me save the error.
The solution was to create baz(), make it #Transactional(propagation=Propagation.REQUIRES_NEW) and call it from foo(). baz() would get a new, fresh transaction and would be able to write to the DB even though it was called from foo() which already had a (broken) transaction.
Another alternative is to use JDBC savepoints to partly roll back.

Categories