Serializable Isolation
Serializable isolation provides behavior equivalent to some serial execution of concurrent transactions. It prevents concurrent transactions from producing results that could not occur under a valid serial ordering.
Serializable is the strongest standard SQL transaction isolation level. The database must ensure that the committed outcome of concurrent transactions is equivalent to executing those transactions one at a time in some order.
The important point is that transactions do not necessarily execute sequentially. A database can still run them concurrently, but it must prevent or resolve concurrency effects that would make the result impossible under any serial ordering. Depending on the database engine, this may use locking, predicate/range locking, optimistic validation, or serialization mechanisms.
Serializable isolation prevents anomalies such as dirty reads, non-repeatable reads, and phantom reads, and it also addresses more subtle write-skew-style anomalies that weaker isolation can permit. The exact implementation and performance characteristics are database-specific.
The trade-off is reduced concurrency or increased transaction-abort/retry behavior. Applications using serializable transactions should be prepared for serialization failures or deadlocks where the database requires a transaction to be retried.
In Java backend systems, this usually means choosing the database driver's or framework's serializable transaction setting when correctness requires it, then designing retry handling and keeping transactions short enough to limit contention.
Key points
- The result must be equivalent to some serial ordering of transactions.
- Concurrent execution is still possible; serialization describes the observable result, not necessarily the execution method.
- Serializable prevents anomalies allowed by weaker isolation levels, including write skew.
- Implementations vary: locking, validation, and other serialization techniques are possible.
- Applications may need to retry transactions after serialization failures or deadlocks.
Interview questions
What does Serializable isolation guarantee?
Serializable isolation guarantees that the committed result of concurrent transactions is equivalent to some serial execution of those transactions. The database can still execute work concurrently. What matters is that concurrency does not produce an outcome that could not have occurred in a valid sequential ordering.
Why can Serializable isolation cause transaction retries?
A database may detect that concurrent transactions cannot safely be committed together while preserving serializability. It can then abort one transaction with a serialization-related error. The application must commonly retry the transaction, provided the operation is safe to retry. Deadlocks can also require retry handling, although a deadlock is a different concurrency condition.
Give an example of an anomaly Serializable prevents that Snapshot Isolation may allow.
Write skew is a classic example. Two transactions can each read overlapping data, find that a business invariant currently holds, and then update different rows so that the invariant is violated. Snapshot Isolation can allow both transactions to commit because they write different rows. Serializable must prevent the resulting state or otherwise make one transaction fail.
How might a database implement Serializable isolation?
There is no single required implementation. A database can use locking approaches, including range or predicate locking, or use optimistic techniques that detect dangerous concurrent dependencies and abort transactions. Some systems use multiversion concurrency control together with additional serialization checks. The implementation affects contention, memory use, latency, and retry behavior, so the database's documentation matters.
How would you use Serializable transactions safely in a Java backend?
I would use Serializable only where the business invariant requires that level of coordination. I would keep the transaction short, make database access predictable, and handle serialization failures and deadlocks with bounded retries and backoff where appropriate. The retry must encompass the whole transaction so that the retried execution observes a fresh database state. I would also monitor abort rates and contention rather than assuming Serializable is free.