Calling saveAndFlush within a JPA Transaction - spring

I have an application that persists data within a transaction using JPA 'save'. A second application accesses this data asynchronously on receiving a message from the first application. However, depending on timing the data is sometimes not accessible by the second application as the main transaction has not yet completed (or is delayed). I am considering changing 'save' to 'saveAndFlush'. Will this ensure that the objects are saved contemporaneously? Will the objects persisted with 'saveAndFlush' be rolled back on a transaction failure?

Objects persisted with saveAndFlush will be rolled back but this will not solve your real problem as changes wont be visible to a request from the second application until the transaction is committed.

Related

Open Session In View OSIV - Does this happen for every request / thread?

I have turned off the OSIV in a Spring project as I have been reading why it (controversially) may be a bit of an anti-pattern. Not wanting to poke that debate as I have seen it gets heated but I am more interested/lost in the technicals.
Either way, I was wondering exactly when does a session become opened? Is it for ANY web request that comes in or is there some way the application knows that it will only be needing a session for certain endpoints? I am guessing the OSIV Filter is basically always called for every request and a hibernate session to the DB is aquired and added to the webrequest/thread?
I.e. is it OSIV for everything or only certain requests get the session bound through the
entire filter chain and then the controller/services and back out?
When they say "session" I am right in assuming that means it has gotten an active jdbc connection and opened connection to the database...even if I may not use it, and that is where the sort of blocking IO problems could occur say if we are waiting on 3rd party responses although we are now out of a #Transactional service method boundary and we get a spike in traffic?
What exactly is opened session wise? Is a database transaction started via the session "just in case" on every request? Or is there just a hibernate session created for each request and then a transaction is only started if a JPA/Hibernate query is started somewhere along the request (with or without #Transactional).
Any clarification would be excellent!
Vlad Mihalcea - OSIV Anti-Pattern
Baeldung - OSIV
Transactions are only started when you run a method annotated with #Transactional. OSIV just eagerly opens/creates a Hibernate session which can be used for lazy loading through out the whole request lifecycle, but the connection is only acquired lazily i.e. on first database access. Once it is acquired, it depends on certain settings when the connection will be released, but usually it is kept open until the session closes.

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.

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

what does suspending a transaction means?

If we are using Propagation Requires_new then it suspends existing transaction and creates a new transaction. So what does it mean to suspends a transaction? what happens to the suspended transaction? what exactly happens behind the scene?
update
what happens to the resource held by suspended transaction?
First of all the question here is a duplication of the thread: How
does transaction suspension work in Spring?. However, I will try
to answer this in a different way.
To understand the working of Spring #Transaction API, we must look inside the transaction propagation mechanism.
Spring managed transaction has physical and logical transactions depending upon the configuration.
PROPAGATION_REQUIRES_NEW uses a completely independent transaction
for each affected transaction scope. The underlying physical
transactions are different and hence can commit or roll back
independently. Here the outer transaction is not affected by an
inner transaction’s rollback status.
When a transaction is suspended, it waits until it can pick up where it left off. This means, the changes that happened while the transaction is suspended are NOT part of the same atomic unit. In other words, the things that happened while the transaction is suspended won’t be rolled back if the suspended transaction (after it comes back to life) fails to commit.
Spring transaction does not expose any API for developers to control this directly, other than the transaction configurations. However if you are using JTA to manage transaction then you can call the suspend and resume methods as below:
Transaction tobj = TransactionManager.suspend();
..
TransactionManager.resume(tobj);
I hope this helps you!

JTA Timeout with nothing to commit

I have a very basic JTA question.
We are using Spring's AOP to apply WebLogicJtaTransactionManager pointcuts on any method in a service class...and we set the tx:method timeout="60".
What is interesting is within that service, we run a select statement to retrieve records from the database (using Hibernate/JPA) and then go do some work that is not database/transactional related. That method takes longer than 60 seconds to run and a timeout exception is never thrown and the transaction is never rolled back. We don't update or create new objects to persist.
To add to that, we have JTA configured to timeout after 180 seconds on WebLogic Server...and the application still doesn't timeout.
The WLS docs say "The transaction timeout in seconds. If the transaction is still in the "active" state after this time (counting from begin()), it is automatically rolled back. Once the transaction moves on to the prepared state, however, this timeout parameter does not apply; the transaction is retried until all the resources are committed."
Would this behavior be related to the fact that there is nothing for the JTA to commit and therefore the timeout doesn't necessarily apply?
Or does it related to the fact that because there is no real database (insert/update/deletes) so the transaction is never in a true active state?
The JTA transaction timeout would only apply to XA based datasources. Can you confirm that that the datasource is setup with an XA database driver ?

Resources