Nested Transaction using Spring and Hibernate - java

In my app, there are multiple steps where many commits to the database will be made sequentially through multiple methods.
Example:
A -> B -> C
-> D
->E
-> F
-> G
A calls B which calls C. Then B calls D. D calls E and so on. All of these methods have some database operations.
As I understand from PROPAGATION_REQUIRED (declarative transaction management - the spring recommended way), if E completes successfully, the transaction (and operations in E will be committed). Now, due to some exception, F should lead to a rollback. I want to have everything rolled-back starting from what A did.
Is this possible via Declarative Transaction management? Or should I use Programmatic Transaction Management?
Thank you.

First, "nested" transactions, in the sense that there are multiple running transactions depending on each other, is not supported, afaik.
Then, propagation=REQUIRED means that all methods with that propagation will:
start a new transaction if there is none exists
participate in an existing transaction if such exists.
This means that in your scenario, a failure in F would rollback the entire transaction (because it is a single transaction, started by A, and propagated to other methods)

Related

Transcations level scope in spring

I'm using Spring Boot 1.4 and trying to understand how does Spring Transaction Management works.
Here is my question:
Lets say I have a service with a method A that is annotated with #Transactional(isolation = SERIALIZABLE) and another method B annotated with #Transactional(isolation = READ_COMMITED).
And then let's imagine that some service X calls these two methods A and B sequentially.
My colleague says that transaction level is set per connection in Spring. Which means that if the same connection from the pool is used for these two sequential calls, then isolation level for both transactions A and B = SERIALIZABLE.
However, to me it seems a bit strange. I would expect that these two transactions would have different level of isolations, because all sql databases allow to set isolation level for a given transaction explicitly.
I was trying to read documentation and couldn't find a place where it would be mentioned that transcation level is assigned to connection.
Can someone judge us on this issue?
If there is no transaction started when calling method A() or B() a new transaction is created when calling the method and gets closed when leaving the method. The used connection returns to pool or gets closed.
This thread explains what happens to the connection when transaction gets closed:
Does Spring close connection after committing transaction?
In case there exists a transaction that wraps both methods, there is only one connection used for both methods; and i guess the isolation level is the one defined by the bigger transaction.

spring nested transactions with different isolation levels

I have two transactional methods A and B. A has isolation level of READ_COMMITTED and B has isolation level of SERIALIZABLE. if B was called inside A, what would be the default behavior here?
is spring going to create a new transaction for B or it will be run in the same transaction? would the isolation level of B be handled correctly?
in case of two threads are accessing A at the same time, what would happen when they reach B call?
In case of B's transaction was rolled back for some reason, would A's transaction be rolled back as well?
Note: let us assume that propagation level is the default one for both A and B.
Any ideas about what happens in such a situation?

JTA - how is transaction registered?

I am using the following piece of code I found online (Here) as an example of JTA Transaction processing:
// Get a UserTransaction
UserTransaction txn = new InitialContext().lookup("java:comp/UserTransaction");
try {
System.out.println("Starting top-level transaction.");
txn.begin();
stmtx = conn.createStatement(); // will be a tx-statement
stmtx.executeUpdate("INSERT INTO test_table (a, b) VALUES (1,2)");
stmtx.executeUpdate("INSERT INTO test_table2 (a, b) VALUES (3,4)");
System.out.print("\nNow attempting to rollback changes.");
txn.rollback();
}
I have a few questions, in general, about the JTA that are drawn from the example above:
I presume the whole point of saying txn.begin and then rollback is to be able to (apperently) rollback TWO SQL statements correct?
Each of the update queries were TRANSACTIONS themselves, right? They must have succeded so that we can get to rollback call at the bottom. Well, if they succeded i.e. commited, how on earth can we roll them back all of a sudden?
The most important question: what happens when we say txn.begin()? I understand from the JTA API that it is supposed to register this transaction with a calling thread by TransactionManager instance. How is TM even linked to the UserTransaction? And finally, how is the txn aware of the fact that we modified the DB twice and is able to speak to DB to roll it back? We have not registered ANY ResourceManagers with it so it should not be aware of any resources being at play...
I am a bit lost here, so any info would be appreciated... Question 3 bothers me the most.
yes, or event just one. It's also the ability of committing the transaction at the end, and thus have the other concurrent transaction only see the new state after the transaction has been committed, and not all the temporary states between the beginning and the end of the transaction (i.e. the I in ACID)
No. An update is an update. It's executed as part of the transaction that you begun previously. If one of them doesn't succeed, you'll have an exception, and can still choose to commit the transaction (i.e. have all the previous updates committed), or to rollback the transaction (i.e. have all the previous updates canceled).
The UserTransaction has a reference to its transaction manager, presumably. When you get a connection from a DataSource in a Java EE environment, the DataSource is linked to the transaction manager of the Java EE container, and rollbacking the JTA transaction will use the XA protocol to rollback all the operations done on all the data sources during the transaction. That's the container's business, not yours.
There's a lot to learn about transactions, but maybe I can give you a head start:
Yes. But you will usually only want to rollback in case of a problem - some step of the transaction could not be completed because of a technical issue (syntax error, table not found, segment overrun, ...) or an application logic problem (customer has not enough funds for all order line items for example).
Given auto commit mode is disabled, the inserts are not committed before you actually commit. They are temporarily applied to the database using a Write-Ahead-Log (PostgreSQL, InnoDB-Engine, Oracle) with sophisticated Multi-Version-Concurrency-Control (MVCC) which determines which state of the database each transactional client can see. A very interesting topic :-).
A UserTransaction is registered with your current Thread. Resources (i.e. Databases or Messaging services) enlist themselves with the UserTransaction. This is usually only necessary when you are using distributed transactions (XA transactions, 2PC).
I suggest to get a good read on SQL programming (for example Head First SQL) and check out the Java EE 6 tutorial.

OpenJPA Transactions - Single or Multiple Entity managers?

I have a DBManager singleton that ensures instantiation of a single EntityManagerFactory. I'm debating on the use of single or multiple EntityManager though, because a only single transaction is associated with an EntityManager.
I need to use multiple transactions. JPA doesn't support nested transactions.
So my question is: In most of your normal applications that use transactions in a single db environment, do you use a single EntityManager at all? So far I have been using multiple EntityManagers but would like to see if creating a single one could do the trick and also speed up a bit.
So I found the below helpful: Hope it helps someone else too.
http://en.wikibooks.org/wiki/Java_Persistence/Transactions#Nested_Transactions
Technically in JPA the EntityManager is in a transaction from the
point it is created. So begin is somewhat redundant. Until begin is
called, certain operations such as persist, merge, remove cannot be
called. Queries can still be performed, and objects that were queried
can be changed, although this is somewhat unspecified what will happen
to these changes in the JPA spec, normally they will be committed,
however it is best to call begin before making any changes to your
objects. Normally it is best to create a new EntityManager for each
transaction to avoid have stale objects remaining in the persistence
context, and to allow previously managed objects to garbage collect.
After a successful commit the EntityManager can continue to be used,
and all of the managed objects remain managed. However it is normally
best to close or clear the EntityManager to allow garbage collection
and avoid stale data. If the commit fails, then the managed objects
are considered detached, and the EntityManager is cleared. This means
that commit failures cannot be caught and retried, if a failure
occurs, the entire transaction must be performed again. The previously
managed object may also be left in an inconsistent state, meaning some
of the objects locking version may have been incremented. Commit will
also fail if the transaction has been marked for rollback. This can
occur either explicitly by calling setRollbackOnly or is required to
be set if any query or find operation fails. This can be an issue, as
some queries may fail, but may not be desired to cause the entire
transaction to be rolled back.
The rollback operation will rollback the database transaction only.
The managed objects in the persistence context will become detached
and the EntityManager is cleared. This means any object previously
read, should no longer be used, and is no longer part of the
persistence context. The changes made to the objects will be left as
is, the object changes will not be reverted.
EntityManagers by definition are not thread safe. So unless your application is single threaded, using a single EM is probably not the way to go.

getCurrentSession hibernate in web

I am writing a web based application with hibernate and jsp/servlet. I have read about the sessionFactory.getCurrentSession and sessionFactory.openSession methods. I know the basic difference between them (using getCurrentSession you don't have to close the connection and when you commit the transaction, your session will automatically close). According to the my understanding, we should opt for getCurrentSession and do it through session-per-request.
Let's consider the following scenario:
Method A calls getCurrentSession and got the current session
In Method A, a transaction is started using the session from step 1
Method A calls Method B, which also has getCurrentSession and starts a transaction
Method B commits its transaction
Control returns to method A and it also commits the transaction
Now my questions are
Will the session found in step 1 and step 3 will be the same session?
If the answer for the question 1 is yes, then how would it handle the commit in step 4? Ideally it should close the session there itself and should throw an exception at step 5.
If the answer for the question 1 is no, then how do you handle such a scenario?
Will the session found in step 1 and step 3 will be the same session?
They should be the same, that's somehow part of the contract of getCurrentSession() and you'll get the Session bound to the thread as long as the unit of work has not been completed (i.e. a transaction has been committed or rolled back). Java Persistence with Hibernate puts it like this (p.481):
All the data-access code that calls getCurrentSession() on the global shared
SessionFactory gets access to the same current Session — if it’s called in the
same thread. The unit of work completes when the Transaction is committed (or rolled back). Hibernate also flushes and closes the current Session and its persistence context if you commit or roll back the transaction. The implication here is that a call to getCurrentSession() after commit or rollback produces a new Session and a fresh persistence context.
And you might also want to read what the javadoc of Session#beginTransaction() says.
If the answer for the question 1 is yes, then how would it handle the commit in step 4. Ideally it should close the session there itself and should give error at step 5.
Step 4 shouldn't be a problem, the Session will be flushed, the Transaction will be committed and the Session closed. But I expect step 5 to fail wih aTransactionException (that's my bet). But let me quote the javadoc of Transaction:
A transaction is associated with a Session and is usually instantiated by a call to Session.beginTransaction(). A single session might span multiple transactions since the notion of a session (a conversation between the application and the datastore) is of coarser granularity than the notion of a transaction. However, it is intended that there be at most one uncommitted Transaction associated with a particular Session at any time.
As underlined above, we are discussing around something that shouldn't happen (i.e. a design problem).
I don't have an answer for your scenario because I would not implement it that way as it seems to be asking for trouble. Instead, I'd start the transaction in C, where C invokes A and B, and have C issue the commit. Skeletally:
public void c(...) {
try {
transaction.begin();
a();
b();
transaction.commit();
catch (Exception e) {
transaction.rollback();
}
}
So here, a() and b() do not commit or rollback - how do they know the entire business task has been completed? They could throw an exception or perhaps return a boolean to tell the caller that something is amiss and a rollback is needed.

Categories