Is it possible to wait transaction lock release with serializable isolation level? - spring

Context:
We've built a JAVA application using spring framework (5.1.8) & spring boot (2.1.6) with the help of Jhipster.
It is a RESTFul application.
Data persistance is done in a PostGRES database managed by Hibernate (5.3.10).
Application constraints:
Because of our context, we have to process most of update transactions in the same order that they happen.
Problem:
All requests are processed by a business function declared as transactionnal (annoted with #Transactionnal(propagation=Propagation.REQUIRED)).
We set the isolation level to SERIALIZABLE to avoid execution of multiple transaction at the same time (concurrency).
However, with this isolation level, we have to manage the transactions repeat for case of concurrency exception.
Is there a way to force to wait transaction lock release before that isolation throws a concurrency exception (serialize access error), like with pessimistic locks ?
We tried to make transaction synchronized but it doesn't work because it seems commits are done outside the transactions.
Any help would be greatly appreciated.

Related

Do we need to add any configuration on client side to avoid transaction retry errors in cockroach database

when there is concurrent updates happening on the same record, transaction 1 is able to update but as per the cockroach database documentation transaction t2 should be on queue, but transaction t2 is immediately failing. Do we need to add any other configuration to make transaction wait in queue instead of it throwing an immedaite retry transaction error. Thanks in advance
Yes, the client should handle transaction retry errors. Note that whenever possible, CockroachDB will auto-retry a transaction internally without notifying the client. CockroachDB will only send a serialization error to the client when it cannot resolve the error automatically without client-side intervention. In this case, cockroach provides client side tools to manually or automatically retry the txn. See the docs here.
As per CockroachDB Documentation
CockroachDB always uses SERIALIZABLE isolation, which is the strongest
of the four transaction isolation levels defined by the SQL standard
and is stronger than the SNAPSHOT isolation level developed later.
SERIALIZABLE isolation guarantees that even though transactions may
execute in parallel, the result is the same as if they had executed
one at a time, without any concurrency.
I am assuming you are using Spring Boot for you application and Spring Data for Database operations.
If there are concurrent updates in the database, it's always good to use SELECT FOR UPDATE when you are using sql query. Similarly, #Locks which does the same in JPA.
#Lock(LockModeType.PESSIMISTIC_READ)
#QueryHints({#QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Employee> findById(Long employeeId);
For more information you can refer documentation.

Spring Boot DB connection release mode

Is there a way to control database connection release strategy in Spring Boot? Something like Hibernate's ConnectionReleaseMode?
My test code would be rougly following:
INSERT query
HTTP call
UPDATE query
INSERT and UPDATE queries are their own methods in a repository bean (either extending CrudRepository, or as a Mybatis #Mapper). HTTP call is in it's own bean.
Now my service bean is where I experiment with different #Transactional settings as my ultimate goal is to have these three steps executed within a single transaction.
The problem is, the HTTP call can take hundreds of millis and Spring is holding the database connection during that time. This quickly leads to an empty connection pool, while the connections themselves are idle.
I have done the same experiments with default configuration using spring-boot-starter-data-jpa and also using mybatis-spring-boot-starter.
The only thing which got me closer to my goal was setting spring.jpa.open-in-view=false for data-jpa, which would release db connections in case of not using #Transactional at all or with propagation set to NEVER. It doesn't work if it's all wrapped in a transactin though.
I'm feeling like I'm missing some vital part of the transaction concept in Spring. Though the Spring reference docs mentions release mode only in relation to JTA transaction manager + JEE container + Hibernate.
Transactions are bound to a connection/session so you can't release the connection in the middle of a transaction. You have to finish the transaction to close/release the connection. Keep in mind that a transaction could abort at any time, and since the HTTP call is not "part of" the transaction, but just runs while the transaction is in progress, it won't help you to keep the transaction open while the HTTP call is running. I'd suggest you go with one of the following solutions:
Use a circuit breaker to cancel the HTTP call if it hits a timeout to have an upper bound for how long a connection/transaction can be open/held
Move the HTTP call out of the transaction, either before or after the transaction
Use two database transactions
Note that you could use a transactional Job Scheduler to schedule a job in the first TX. The job could then, with at least once semantics, try to invoke the HTTP call and then continue with the second transaction or do some compensation if something fails.

Spring Boot - Change Transaction Manager handling #Transactional annotation?

I'm currently using the #Transactional annotation to save data to a database, and would like to know how to change the transaction so it affects other resources like message queues. I didn't set up beans or anything to make dealing with the database transactional - I just added the #Transactional annotation and nothing else.
You are thinking to enter complicated and slow world called two phase commit transactions. For such case you would need to use distributed transactions manager like Atomikos. JEE has JTA (Java Transaction API) abstractions for it.
I would suggest to avoid this world as much as possible, because of slowness.
Here are few Spring Boot examples I created. They combine distributed transactions with database and JMS queue.
Combining even more than two data sources into distributed transactions would be extremely slow.

How application can be notified when Spring Transaction Manager rollbacks a SQL transaction?

In Spring based application, Transaction Manager is responsible for committing or rolling back SQL transactions.
My application uses a custom cache for some part of persistent data.
This cache is not managed by Spring nor Hibernate.
If a SQL transaction encounters errors and must be rolled back, then cache modifications should be rolled back as well.
My question is, how to register an event listener or callback which will call my cache.evict() method when Spring Transaction Manager rolls back a transaction?
You can use TransactionSynchronizationAdapter for this. For reference, you can look at this: Spring - commit JMS Transaction after JPA transaction
In the answer given in the link, the synchronization is registered for afterCommit. In your case, it would be afterCompletion. In that implementation, you will need to check if the transaction is in a rolled back state and do the cache eviction.
There are lots of ways of doing this...
You can use application events if you want... Application Events in Spring Framework 4.2
You can throw a custom runtime exception and you can handle it in your exception handler (if you're using spring MVC). but here I don't recommend to do any important operations like clearing of cache here... Exception handling in Spring MVC
You can use a combination of #1 and #2. You can send an event that will eventually throw a runtime exception that you handle it in UI (spring mvc or whatever you use). This is how I would do it
You can throw an exception and anyone calling your bean will get the custom transaction exception you want and will have to deal with notification... I don't recommend this

Is there any way to set transaction isolation level in EJB in its deployment descriptor itself?

Is there any way to set the transaction isolation level in EJB in its deployment descriptor itself? Do we have that flexibility?
I meant transaction isolation level. For bean managed transactions we can set the isolation in a resource manager API like JDBC. I was thinking if in any way we can set the container managed transactions isolation level in a deployment descriptor?
The transaction isolation level is a property of the resource that participates in a transaction. It's unrelated to whether the user manages the transaction (Bean Managed Transactions, BMT) or that the container does that (Container Managed Transactions, CMT).
The only thing EJB does is start, propagate and commit or rollback transactions via JTA. What exactly constitutes as a transaction for each resource is up to that resource.
See this answer for a more detailed explanation: How do i set the Transaction Isolation in EJB?

Resources