How do you handle transactions in your application ?
Step 1: Annotate the class or method with @Transactional :
@Transactional public class FooService { //... }
Step 2: In the main class add @EnableTransactionManagement
Where should we put the @Transactional ? In Service or DAO Layer?
The “service” is the best place for putting @Transactional annotation. Service layer should hold the detail-level use case behavior for a user interaction that would logically go in a transaction.
Dirty Read Vs Non-Repeatable Read Vs Phantom Read:
Dirty Read:
A Dirty read is a situation when a transaction reads data that has not yet been committed. Suppose Transaction T1 reads some data and modifies it but it has not committed the same. In the meantime Transaction T2 reads the older data. This is called Dirty Read.
Non-Repeatable Read:
Non Repeatable read occurs when a transaction reads the same row more than once and gets a different value each time.
For eg., a transacion (T1) reads a data, then after some time it reads again, and if everytime it gets the same data data, this is called Repeatable Read, which means – every time a transaction reads the data the data is getting repeated.
In the meantime, some other transaction (T2) do a commit and overwrite the same data. Now, when T1 tries to read the data, it has different value, this is Non-Repeatable Read. Basically, this problem is related to reading inconsistency, unlikely in Dirty read where you have a stale data, on which you have already started some processes.
Phantom Read:
Phantom Read occurs when same query executing multiple times returns different number of data rows.
For example, a transaction (T1) reads n rows of data. After that transaction T2 updates some new row(s) of data. Now if the previous transaction T1 reads the database it gets m rows of data (a phantom of records will be fetched, i.e. different number of records will be fetched). This is phantom read.
So basically here the number of records changes every time we call a DB, unlikely in Non-Repeatable read where the data changes of a single record and not of multiple records.
for eg.:
T1: Select count(*) from Employee;
T2: Insert into Employee values(1234, “Prasanna”, 44);
Now T1 if executed again will pick more records.
What’s the difference between a dirty read and the non-repeatable read? Is it not the same thing? reading the wrong result due to others’ updating?
Accessing an updated value that has not been committed is considered a dirty read because it is possible for that value to be rolled back to its previous value. If you read a value that is later rolled back, you will have read an invalid value.
So, non-repeatable read consists in reading two different committed values, whereas dirty read consists in reading a value that hasn’t been committed yet. Quite different.
A non-repeatable read is one in which data read twice inside the same transaction cannot be guaranteed to contain the same value.
In REPEATABLE READ isolation levels Shared locks are acquired. This prevents data modification when other transaction is reading the rows and also prevents data read when other transaction are modifying the rows. But this does not stop INSERT operation which can add records to a table getting modified or read on another transaction. This leads to PHANTOM reads.
PHANTOM READS: Data getting changed in current transaction by other transactions is called Phantom Reads. New rows can be added by other transactions, so you get different number of rows by firing same query in current transaction.
Transaction Isolation Levels:
READ_UNCOMMITTED: This isolation level states that a transaction may read data that is still uncommitted by other transactions.
READ_COMMITTED: A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur.
REPEATABLE_READ: A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur.
SERIALIZABLE: A constant indicating that dirty reads, non-repeatable reads, and phantom reads are prevented.
Besides the above 4 Isolation level there is an 5 level- DEFAULT.
DEFAULT: If you do not mention anything then it will take it as DEFAULT. Here it will use the default isolation level of the underlying database.
@Transactional (isolation=Isolation.READ_COMMITTED)
Dirty Read | Non Repeatable Read | Phantom Read | |
READ_UNCOMMITTED | Possible | Possible | Possible |
READ_COMMITTED | Solved | Possible | Possible |
REPEATABLE_READ | Solved | Solved | Possible |
SERIALIZABLE | Solved | Solved | Solved |
Transaction Propagation Levels:
REQUIRED: (default)
Indicates that the target code needs an active transaction. If an transaction is already there it will run in the same transaction, if there is no transaction then it will run in a new transaction.
REQUIRES_NEW:
Indicates that the target code will always start a new transaction, immaterial if there is already an active transaction or not. If an existing transaction is there it will suspend that.
MANDATORY:
Indicates that the target code needs an active transaction. If there is no active transaction then it will throw an exception. Difference between REQUIRED and MANDATORY is that the former will not throw an exception if it doesn’t get an active transaction, it will try to create a new transaction.
SUPPORTS:
It is a good boy. It supports everything, if it get an active transaction its good, if it doesn’t gets then also no problem.
Methods which fetch data are the best candidates for this option.
NOT_SUPPORTED:
Indicates that the target code doesn’t require the transaction context to be propagated.
Execute non-transactionally, suspend the current transaction if one exists.
Mostly those methods which run in a transaction but perform in-memory operations are the best candidates for this option.
NEVER:
It is the bad boy. If it gets an active transaction it will throw an exception.
Execute non-transactionally, throw an exception if a transaction exists.
This option is mostly not used in projects.
@Transactional(propagation=Propagation.MANDATORY)
If not specified, the default propagation behavior is REQUIRED.