Repeatable Read Isolation
Repeatable Read ensures that repeated reads of the same data within a transaction remain consistent according to the database's isolation semantics. It is stronger than Read Committed, but its handling of concurrent inserts, updates, and serialization anomalies varies by database implementation.
Transaction isolation controls what effects from concurrent transactions a transaction can observe. With Repeatable Read, once a transaction reads a row, a later read of that same row does not unexpectedly expose a newer committed version under the database's defined semantics.
Many MVCC databases implement Repeatable Read using a transaction-level snapshot. In such systems, ordinary reads can continue to see data as of the transaction's snapshot even when other transactions commit changes afterward. The exact behavior depends on the database engine and its concurrency-control model.
Repeatable Read does not universally mean that every query in the transaction sees exactly the same result set. In particular, whether a newly inserted row matching a predicate can appear later is database-specific. Some systems provide snapshot-style behavior, while others use locking or different mechanisms with different anomaly guarantees.
In Java applications, the isolation level is commonly selected through JDBC or a framework such as Spring. For example, `Connection.TRANSACTION_REPEATABLE_READ` represents the JDBC Repeatable Read level, while Spring can request it with `@Transactional(isolation = Isolation.REPEATABLE_READ)`. The database ultimately determines the precise concurrency behavior.
Key points
- Repeated reads of already-observed data are protected against certain concurrent changes.
- Repeatable Read is stronger than Read Committed.
- Implementation details differ across database systems.
- Predicate and phantom behavior should not be assumed without checking the database's semantics.
- In Java, JDBC and Spring expose Repeatable Read as a transaction isolation option.
Interview questions
What problem does Repeatable Read solve?
It prevents certain changes made by concurrent transactions from causing a transaction to get inconsistent results when it reads the same data again. For example, after a transaction reads a row, another transaction may update and commit that row, but the first transaction should not unexpectedly observe the new version when it rereads it under Repeatable Read semantics. The exact behavior is database-dependent.
How does Repeatable Read differ from Read Committed?
Under Read Committed, separate statements in one transaction can generally observe different committed versions as other transactions commit. Repeatable Read provides stronger guarantees for data that the transaction has already read. In MVCC systems, this is often implemented with a transaction-level snapshot or equivalent mechanism. The precise guarantees should be checked for the specific database.
Does Repeatable Read prevent phantom reads?
There is no database-independent yes-or-no answer. The SQL isolation-level name does not guarantee identical behavior across database engines, and implementations use different concurrency-control mechanisms. Some MVCC implementations provide snapshot behavior that prevents a transaction's ordinary reads from observing newly committed matching rows, while other systems can have different semantics. In an interview, name the database before making a precise claim.
How would you configure Repeatable Read in a Java backend?
With JDBC, a connection can request `Connection.TRANSACTION_REPEATABLE_READ`. In Spring, a transaction can request `Isolation.REPEATABLE_READ` through `@Transactional`. The framework setting is only a request for a particular isolation level; the actual behavior is governed by the database and transaction configuration. I would also verify connection-pool behavior and the database's supported isolation levels.
Why not use Serializable for every transaction if it is stronger?
Serializable provides stronger concurrency guarantees, but stronger isolation can reduce concurrency or increase contention, blocking, retries, or serialization failures depending on the implementation. Many workloads do not require that level of coordination. The appropriate choice depends on the correctness requirements, transaction duration, workload, and database implementation. I would choose the weakest isolation level that satisfies the application's correctness requirements and validate it with concurrency tests.