spring nested transactions with different isolation levels - java

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?

Related

Transaction isolation and concurrency

I'm trying to build an application in Java(JDK1.8) with Connector/J and MySql. I'm told that Serializable is the highest level, but it affects performance, so Serializable is not commonly adopted.
But consider this situation:
There are two commits which are going to update the fields of the same row (commit A and commit B). If A and B happens concurrently and the isolation level is not Serializable, there would be data races, which makes the fields inconsistent. But in Serializable level, the two updates won't happen at the same time, so either A happens before B or B happens before A, and the row will either be in version A or in version B, but not some mix of A and B.
I thought Atomicity of ACID guarantees the synchronization of A and B. But it seems that the definition of Atomicity only guarantees one transaction happens "all or nothing", it says nothing about the concurrent commits.
So should I use Serializable to prevent the data race? Which one of the ACID actually guarantees the atomicity of one update?
No. To avoid the problem you described you don't need "serializable". There are also other isolation levels. What you are afraid of can only happen with "read uncommitted". For any other isolation level the fields within a single record will always be consistent.

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.

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.

Where does the responsibility lie to ensure the ACID properties of a transaction?

I was going through ACID properties regarding Transaction and encountered the statement below across the different sites
ACID is the acronym for the four properties guaranteed by transactions: atomicity, consistency, isolation, and durability.
**My question is specifically about the phrase.
guaranteed by transactions
**. As per my experience these properties are not taken care by
transaction automatically. But as a java developer we need to ensure that these properties criteria are met.
Let's go through for each property:-
Atomicity:- Assume when we create the customer the account should be created too as it is compulsory. So now during transaction
the customer gets created while during account creation some exception oocurs. So the developer can now go two ways: either he rolls back the
complete transaction (atomicity is met in this case) or he commits the transaction so customer will be created but not the
account (which violates the atomicity). So responsibility lies with developer?
Consistency:- Same reason holds valid for consistency too
Isolation :- as per definition isolation makes a transaction execute without interference from another process or transactions.
But this is achieved when we set the isolation level as Serializable. Otherwis in another case like read commited or read uncommited
changes are visible to other transactions. So responsibility lies with the developer to make it really isolated with Serializable?
Durability:- If we commit the transaction, then even if the application crashes, it should be committed on restart of application. Not sure if it needs to be taken care by developer or by database vendor/transaction?
So as per my understanding these ACID properties are not guaranteed automatically; rather we as a developer sjould achieve them. Please let me know
if above understanding regarding each point is correct? Would appreciate if you folks can reply for each point(yes/no will also do.
As per my understanding read committed should be most logical isolation level in most application, though it depends on requirement too.
The transactions guarantees ACID more or less:
1) Atomicity. Transaction guarantees all changes are made or none of them. But you need to manually set the start and end of a transaction and manually perform commit or rollback. Depending on the technology you use (EJB...), transactions are container-managed, setting the start and end to the whole "method" you are creating. You can control by configuration if a method invoked requires a new transaction or an existing one, no transaction...
2) Consistency. Guaranteed by atomicity.
3) Isolation. You must define the isolation level your application needs. Default value is defined depending upon the database, container... The commonest one is READ COMMITTED. Be careful with locks as can cause dead-lock depending on your logic and isolation level.
4) Durability. Managed entirely by the database. If your commit executes without error, nearly all database guarantees durability of changes, but some scenarios can cause to not guarantee that (writes to disk are cached in memory and flushed later...)
In general, you should be aware of transactions and configure it in the container of declare by code the star and end (commit, rollback).
Database transactions are atomic: They either happen in their entirety or not at all. By itself, this says nothing about the atomicity of business transactions. There are various strategies to map business transactions to database transactions. In the simplest case, a business transaction is implemented by one database transaction (where a business transaction is aborted by rolling back the database one). Then, atomicity of database transactions implies atomicity of business transactions. However, things get tricky once business transactions span several database transactions ...
See above.
Your statement is correct. Often, the weaker guarantees are sufficient to prove correctness.
Database transactions are durable (unless there is a hardware failure): if the transaction has committed, its effect will persist until other transactions change the data. However, calling code might not learn whether a transaction has comitted if the database or the network between database and calling code fails. Therefore
If we commit the transaction, then even if application crash, it should be committed on restart of application.
is wrong. If the transaction has committed, there is nothing left to do.
To summarize, the database does give strong guarantees - about the behaviour of the database. Obviously, it can not give guarantees about the behaviour of the entire application.

Nested Transaction using Spring and Hibernate

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)

Categories