How it works
A transaction acquires locks before accessing protected data. Shared locks allow multiple readers; exclusive locks allow one writer and block conflicting readers or writers that need locks on the same data. For example, a reservation transaction can lock a seat row before checking and changing its availability.
The two phases describe lock acquisition and release, not two rounds of communication. During the growing phase, a transaction can acquire locks but cannot release them. Once it releases its first lock, it enters the shrinking phase and cannot acquire any new locks.
When all relevant accesses follow this protocol, 2PL guarantees conflict serializability: the result is equivalent to some serial ordering of transactions. Basic 2PL can release locks before commit, however, so it does not by itself prevent other transactions from depending on uncommitted writes.
Strict 2PL keeps exclusive locks until commit or abort, preventing other transactions from reading or overwriting those uncommitted writes. Holding both shared and exclusive locks until completion is often called rigorous 2PL, although terminology varies across sources.
Lock scope must cover the invariant. Locking existing reservation rows does not necessarily prevent another transaction from inserting a conflicting reservation. Rules based on query results may require key-range or predicate locks, or a schema with stable inventory rows that every competing transaction locks.
Databases usually manage these locks; applications define transaction boundaries and may request locking reads such as SELECT ... FOR UPDATE. Exact behavior depends on the database and isolation level, especially when MVCC is involved. Two transactions can deadlock by locking resources in opposite orders, so the database must detect or otherwise resolve the wait and abort a transaction.
A worked example
Reserve three hotel nights atomically
A hotel stores one inventory row per room type and date. Each of three consecutive nights has one room left. Requests A and B both want all three nights. In a short transaction, A locks the three rows in date order, checks availability, decrements each count, and creates a reservation hold. B waits on the first conflicting lock. After A commits and releases its locks, B acquires them, sees zero availability, and rejects the request without decrementing anything. If any night is unavailable, the transaction rolls back the whole reservation. Payment happens outside this transaction; the durable hold has an expiration time. This works only if every competing inventory update follows the same locking discipline.
Trade-offs to say out loud
- Correctness versus concurrency
- Conflicting operations wait rather than proceed independently, preserving invariants but limiting throughput on hot rows.
- Deadlocks and retries
- Transactions can form a cycle of lock waits, requiring deadlock handling and a safe retry of the entire aborted transaction.
- Lock granularity
- Fine-grained locks allow more concurrency but consume more lock-management resources, while coarse locks block unrelated work.
- Transaction duration
- Holding locks across slow queries, user interactions, or external calls increases contention and tail latency.
- Recovery behavior
- Basic 2PL can allow cascading aborts, while strict 2PL prevents dependencies on uncommitted writes by retaining exclusive locks.
- Distributed coordination
- 2PL controls conflicting access but does not by itself make a transaction commit atomically across independent databases.
When to reach for it
- Concurrent requests update scarce inventory, account balances, or another shared resource whose rules cannot tolerate conflicting decisions.
- A decision depends on reading and updating several rows together, such as reserving inventory for every night of a hotel stay.
- Conflicts are frequent enough that optimistic retries may waste substantial work, and short lock waits are acceptable.
- The interviewer asks how database transactions actually prevent lost updates, double allocation, or write skew under the chosen isolation level.
How to bring it up in the interview
- Start with the invariant and transaction boundary: identify exactly which records or ranges must be protected and when the locks can be released.
- Describe the concrete database operations rather than just saying 'use 2PL'; explain locking reads, validation under the lock, updates, and commit.
- Name the variant and its guarantee: basic 2PL gives conflict serializability, while strict 2PL additionally prevents access to uncommitted writes through conflicting locks.
- Expect a deadlock follow-up: use a consistent lock order where possible, keep transactions short, and retry aborted transactions with bounded backoff.
- Be ready to defend the choice against optimistic locking or MVCC-based serializable execution, and explain that two-phase commit solves a different problem.
Common mistakes
- Confusing two-phase locking with two-phase commit: one controls concurrency, while the other coordinates an atomic commit decision across participants.
- Claiming that every SQL transaction or every SELECT ... FOR UPDATE provides serializable execution; guarantees depend on the engine, isolation level, and all relevant accesses.
- Locking existing rows but ignoring inserts that can change a query result and violate a predicate-based invariant.
- Holding a database transaction open while a customer checks out or an external payment provider responds, instead of recording a durable, expiring business hold.
- Assuming locks eliminate failure handling; deadlocks, aborted transactions, and uncertain client outcomes still require retries and idempotency.
Where it comes up
Interview questions where two-phase locking is part of a strong answer, and why.
- Design a ticket booking system like TicketmasterShort locking transactions can turn available seats into durable holds without allowing concurrent buyers to allocate the same seat.
- Design a hotel booking systemLocking date-specific inventory rows protects an atomic multi-night reservation against competing bookings.
- Design a stock trading app like RobinhoodConcurrent orders need transactional protection when checking and reserving the same available cash or shares.
- Design a payment systemConcurrent refunds and payouts require protected reads and updates so their combined effect cannot exceed refundable or spendable funds.
- Design a wire transfer systemLocking the relevant account state within a ledger transaction can preserve balance rules when multiple transfers compete for funds.
Questions people ask
What are the two phases of two-phase locking?
The growing phase allows a transaction to acquire locks but not release them. The shrinking phase starts with its first lock release; after that, it cannot acquire new locks. The phases are about lock behavior, not prepare and commit messages.
What is the difference between 2PL and strict 2PL?
Basic 2PL guarantees conflict serializability but may release locks before commit, allowing dependencies on uncommitted writes. Strict 2PL holds exclusive locks until commit or abort, preventing dirty reads and dirty writes through conflicting locks. Holding all shared and exclusive locks until completion is commonly called rigorous 2PL.
Can two-phase locking cause deadlocks?
Yes. One transaction can hold a lock that another needs while waiting for a lock held by that other transaction. Consistent acquisition order reduces this risk, but systems still need deadlock handling and transaction retries; 2PL itself does not guarantee deadlock freedom.