How does transaction suspension work in Spring? - java

My question is basically the same as is here, but I'm not satisfied with the answer so I'm writing this question.
In Spring Framework manual it is stated that for a PROPAGATION_REQUIRES_NEW the current transaction will be suspended. How is this actually implemented? I know that most databases don't support nested transactions and can have only one transaction running in one connection. This means that you can't just "not use" original transaction and start a new one - before starting new one you must commit or rollback original transaction.
Example:
START TRANSACTION
SELECT ...
UPDATE ...
-- Now we run method with PROPAGATION_REQUIRES_NEW
-- How do we "suspend" transaction so we can start new one?
START TRANSACTION
UPDATE ...
COMMIT
-- We returned from the method, result was commited
-- Now we'd like to "unsuspend" the original transaction so it can be commited/rollbacked, but how?
Or is this possibly implemented using another connection (Session object)? So that we stop using the original connection and create a new one where we can start new transaction?
I am missing here something so obvious that nobody cares to explain it (at least not in Spring docs, Spring in Action, Spring persistence with Hibernate).
Thanks a lot!

The point of suspending a transaction is to change the current transaction for a thread to a new one. This would NOT line up with the semantics of nested transactions because the new and suspended transactions are completely independent of each other. There is no connection-level API to support suspending transactions so this has to be done by using a different connection. If you are using JTA with Spring, this is done by the JTA transaction manager. If you are using DataSourceTransactionManager, you can look in the code and see that it will be saving off the current connection as a "suspended resource" and grabbing a new connection from the data source for the new transaction.

Related

What is a transaction boundary in hibernate

I have 2 questions related to each other
Q1 What exactly is a transaction boundary in hibernate/Spring Data JPA.
I am new to JPA , so please give a very basic example so I can understand as I tried to read multiple blogs but still not very clear.
Q2 And on top of it, what does this mean-
In hibernate, persist() method guarantees that it will not execute an INSERT statement if it is called outside of transaction boundaries, save() method does not guarantee the same.
What is outside and inside of a transaction boundary and how executions are performed outside boundaries?
A transaction is a unit of work that is either executed completely or not at all.
Transactions are fairly simple to use in a typical relational database.
You start a transaction by modifying some data. Every modification starts a transaction, you typically can't avoid it. You end the transaction by executing a commit or rollback.
Before your transaction is finished your changes can't be seen in other transactions (there are exceptions, variations and details). If you rollback your transaction all your changes in the database are undone.
If you commit your changes your changes become visible to other transactions, i.e. for other users connected to the same database. Implementations vary among many other things if changes become visible only for new transactions or also for already running transactions.
A transaction in JPA is a database transaction plus additional stuff.
You can start and end a transaction by getting a Transaction object and calling methods on it. But nobody does that anymore since it is error prone. Instead you annotate methods with #Transaction and entering the method will start a transaction and exiting the method will end the transaction.
The details are taken care of by Spring.
The tricky part with JPAs transactions is that within a JPA transaction JPA might (and will) choose to delay or even avoid read and write operations as long as possible. For example when you load an entity, and load it again in the same JPA transaction, JPA won't load it from the database but return the same instance it returned during the first load operation. If you want to learn more about this I recommend looking into JPAs first level cache.
A transaction boundary it's where the transaction starts or is committed/rollbacked.
When a transaction is started, the transaction context is bound to the current thread. So regardless of how many endpoints and channels you have in your Message flow your transaction context will be preserved as long as you are ensuring that the flow continues on the same thread. As soon as you break it by introducing a Pollable Channel or Executor Channel or initiate a new thread manually in some service, the Transactional boundary will be broken as well.
some other people ask about it - look it up.
If you do not understand something write to me again more accurately and I will explain.
I really hope I helped!

java : when can a rollback fail in jpa?

I'm using JPA and I begin a transaction before a function is called which will in turn store some data into the database. The transaction is then ended after the function call is executed. But I also use entityManager.flush() and entityManager.clear() guessing that memory will be freed on using clear(). before ending the transaction. Please do correct me. When I executed the program, it failed to roll back.
I also tried removing the flush() and clear(), still I'm not able to roll back. When can a roll back fail in my scenario when I'm using clear and flush?
I also use entityManager.flush() and entityManager.clear() guessing
that memory will be freed on using clear().
Well you should stop guessing and start reading some documentation.
EntityManager flushes on tx.commit() by itself, and entity manager is cleared when it is closed.
If you are using container manager transactions, you should rather not worry about flushing and clearing entity managers. If you are using JavaSE then your normal workflow with DB should look like this:
Create new entity manager
Start transaction
Do your job - delete/update/insert whatever
Commit transaction / Rollback if needed
Close entity manager
Normally this would be closed in small try-catch-finally block
EntityManager is lightweight and short living component. You should create one just when you need it, and close it right after you use it.
What is supposed to be a singleton instance, and created (most cases) only once is EntityManagerFactory

Hibernate session and concurrency

I am quite new with Hibernate and I have this newbie question in my head the clear answer to which I couldn't find anywhere online.
In my multithreaded application I want to use Hibernate for data persistence. The app by nature is event based, means that new event will spawn new thread to process incoming data. From one of online Getting Started tutorials I implemented Hibernate Session Factory which will create single session object and will return it upon HibernateUtil.getSessionFactory().getCurrentSession(). From same tutorial I use this factory as follows:
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
/*
do smth here
*/
session.getTransaction().commit();
What I want to clarify is since there is only one session object shared across different threads will the concurrency work with this code?
For example I am not clear how it will handle situations when 1st thread started transaction, then 2nd thread started transaction, then 1st thread tries to commit transaction, which transaction will it commit? Since I am apllying HQL or Criteroins to Session object, would it know which transaction it should be applied to?
No need to worry about a session being shared across multiple threads. By default the SessionFactory will bind a Session per thread in each of the 3 possible configurations. Here it is an extract from Hibernate 4 docs:
However, as of version 3.1, the processing behind SessionFactory.getCurrentSession() is now pluggable. To that end, a new extension interface, org.hibernate.context.spi.CurrentSessionContext, and a new configuration parameter, hibernate.current_session_context_class, have been added to allow pluggability of the scope and context of defining current sessions.
...
Out-of-the-box, Hibernate comes with three implementations of this interface:
org.hibernate.context.internal.JTASessionContext: current sessions are tracked and scoped by a JTA transaction. The processing here is exactly the same as in the older JTA-only approach. See the Javadocs for details.
org.hibernate.context.internal.ThreadLocalSessionContext:current sessions are tracked by thread of execution. See the Javadocs for details.
org.hibernate.context.internal.ManagedSessionContext: current sessions are tracked by thread of execution. However, you are responsible to bind and unbind a Session instance with static methods on this class: it does not open, flush, or close a Session.
SessionFactory - It shared single object to whole application.It is threadsafe.
Session - It will be created for every application request. It does share with any other object and It is not threadsafe.

Spring transaction REQUIRED vs REQUIRES_NEW : Rollback Transaction

I have a method that has the propagation = Propagation.REQUIRES_NEW transactional property:
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUser(final UserBean userBean) {
//Some logic here that requires modification in DB
}
This method can be called multiple times simultaneously, and for every transaction if an error occurs than it's rolled back (independently from the other transactions).
The problem is that this might force Spring to create multiple transactions, even if another one is available, and may cause some performance problems.
Java doc of propagation = Propagation.REQUIRED says: Support a current transaction, create a new one if none exists.
This seems to solve the performance problem, doesn't it?
What about the rollback issue ? What if a new method call rolls back while using an existing transaction ? won't that rollback the whole transaction even the previous calls ?
[EDIT]
I guess my question wasn't clear enough:
We have hundreds of clients connected to our server.
For each client we naturally need to send a feedback about the transaction (OK or exception -> rollback).
My question is: if I use REQUIRED, does it mean only one transaction is used, and if the 100th client encounters a problem the 1st client's transaction will rollback as well ?
Using REQUIRES_NEW is only relevant when the method is invoked from a transactional context; when the method is invoked from a non-transactional context, it will behave exactly as REQUIRED - it will create a new transaction.
That does not mean that there will only be one single transaction for all your clients - each client will start from a non-transactional context, and as soon as the the request processing will hit a #Transactional, it will create a new transaction.
So, with that in mind, if using REQUIRES_NEW makes sense for the semantics of that operation - than I wouldn't worry about performance - this would textbook premature optimization - I would rather stress correctness and data integrity and worry about performance once performance metrics have been collected, and not before.
On rollback - using REQUIRES_NEW will force the start of a new transaction, and so an exception will rollback that transaction. If there is also another transaction that was executing as well - that will or will not be rolled back depending on if the exception bubbles up the stack or is caught - your choice, based on the specifics of the operations.
Also, for a more in-depth discussion on transactional strategies and rollback, I would recommend: «Transaction strategies: Understanding transaction pitfalls», Mark Richards.
If you really need to do it in separate transaction you need to use REQUIRES_NEW and live with the performance overhead. Watch out for dead locks.
I'd rather do it the other way:
Validate data on Java side.
Run everyting in one transaction.
If anything goes wrong on DB side -> it's a major error of DB or validation design. Rollback everything and throw critical top level error.
Write good unit tests.

Differences between requires_new and nested propagation in Spring transactions

I can't understand the behavior difference between the PROPAGATION_REQUIRES_NEW and PROPAGATION_NESTED propagation policies. It seems to me that in both cases, the current process is rollbacked but not the whole transaction. Any clue?
See this link: PROPAGATION_NESTED versus PROPAGATION_REQUIRES_NEW? Juergen Hoeller explain it very well. -- the Spring Source Forum is completely offline since February 28, 2019, but you can read the relevant part of the article in the quote below
PROPAGATION_REQUIRES_NEW starts a new, independent "inner" transaction
for the given scope. This transaction will be committed or rolled back
completely independent from the outer transaction, having its own
isolation scope, its own set of locks, etc. The outer transaction will
get suspended at the beginning of the inner one, and resumed once the
inner one has completed. ...
PROPAGATION_NESTED on the other hand starts a "nested" transaction,
which is a true subtransaction of the existing one. What will happen
is that a savepoint will be taken at the start of the nested
transaction. Íf the nested transaction fails, we will roll back to
that savepoint. The nested transaction is part of of the outer
transaction, so it will only be committed at the end of of the outer
transaction. ...
PROPAGATION_REQUIRES_NEW : uses a completely independent transaction for each affected transaction scope. In that case, the underlying physical transactions are different and hence can commit or roll back independently, with an outer transaction not affected by an inner transaction's rollback status.
PROPAGATION_NESTED : uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions.
check spring documentation
Please find the difference
1.) Use of NESTED Transaction
Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
Nested transaction is supporting by Spring
2.)Use of REQUIRED Transaction
Support a current transaction, create a new one if none exists.
. It means for banking domain like withdraw,deposit, update the transaction
3.) Use of REQUIRES_NEW Transaction
Create a new transaction, and suspend the current transaction if one exists.

Categories

Resources