A transaction is a unit of work that is treated in a coherent and reliable way independant of other transactions.
This unit of work may, for example, be composed of database operations and messaging services operations. If a part of this unit of work fails, the whole unit is considered as having failed.
Database transactions should be atomic, consistend, isolated, durable: ACID.
- Atomicity ensures that either the whole work is done or nothing is done.
- Consistency guarantees the respect of integrity constraints.
- Isolation defines how the changes made by a current operation are visible from other current operations.
- Durability guarantees that transactions that are successfully commited will survive permanently and cannot be undone by system failure.
Transactions may be global (they work across several transactionnal ressources, for example a transaction may be composed of DB operations and messaging operations) or local (they only work with one transactional resource).
Transactions have different properties that define their behaviour: propagation, isolation, read-only, timeout.
- Propagation specifies how code behaves when a transaction method is executed when another transaction context exists (continue running in the same transaction, suspend the running transaction and run in a new transaction context,…).
- Isolation was described as a member of ACID, and is composed of several levels.
- Read-only indicates that no write operations will be done during the transaction.
- Timeout indicates the time after which a transaction must be rolled back.
Isolation levels:
- Serializable provides the highest transaction isolation. This emulates serial transactions, as if transactions occured the one after the other.
- Repeatable read occurs when a transaction re-reads data and the data cannot have been modified by another transactions’ commit since the initial read.
- Read committed occurs when a transaction can only access data that was committed before the select query began.
- Read uncommitted (also known as dirty read) occurs when a transaction reads data written by concurrent uncommitted transaction.
The three phenomena that must be prevented are:
- Dirty reads: Occur when a transaction reads data written by concurrent uncommitted transaction.
- Non-repeatable reads: Occur when a transaction re-reads data it has previously read and finds that data has been modified by another transaction (that committed since the initial read).
- Phantom reads: Occur when a transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.
This matrix shows how isolation levels may be used to avoid these phenomena:
| Isolation Level |
Dirty Read |
Non-Repeatable Read |
Phantom Read |
| Read uncommitted |
Possible |
Possible |
Possible |
| Read committed |
Not possible |
Possible |
Possible |
| Repeatable read |
Not possible |
Not possible |
Possible |
| Serializable |
Not possible |
Not possible |
Not possible |
Note that transactions are different in DB and in programming languages. Programming languages introduce the concept of propagation.
Propagation levels in the Spring framework:
- Required : In the case that during a running transaction, a second one is started, the second transaction operations are executed in the same existing context of the first transaction.
- RequiresNew : Each transaction uses a completely different context.
- Nested : Uses a single physical transaction with several savepoints that it can rollback to.