What does it mean for a concurrent schedule to be serialisable, and how does two-phase locking guarantee it?
A schedule is serialisable when its effect matches running the same transactions one after another in some order, which is the criterion isolation is defined against. Two-phase locking achieves it by forbidding a transaction from acquiring any lock after releasing one, and the price is deadlock.
What the interviewer is scoring
- Does the candidate define correctness as equivalence to some serial order rather than to a specific one
- Whether they can explain why the growing and shrinking phases are what produce the guarantee
- That strict 2PL is distinguished from plain 2PL and the reason for holding locks to commit is given
- Whether deadlock is presented as the unavoidable consequence rather than an implementation defect
- Does the candidate contrast the locking approach with a version-based one
Answer
The correctness criterion
Running transactions one at a time is obviously correct and unacceptably slow. Everything in concurrency control is an attempt to interleave operations while preserving the correctness that the serial execution would have given you, so the first thing to be precise about is what "correct" means here.
A schedule — a particular interleaving of the reads and writes of several transactions — is serialisable if its effect is equivalent to some serial execution of those same transactions. Not a specific one. If T1 and T2 run concurrently and the outcome matches either "T1 then T2" or "T2 then T1", the schedule is correct. The database is under no obligation to produce the order you expected, only to produce a result consistent with one of them.
That "some" is what candidates most often drop, and it is the whole point. It is why two concurrent transfers between accounts can be interleaved freely as long as the final balances match one of the two orderings, and why a system that insisted on a particular order would be needlessly serial.
Why conflicts are the only thing that matter
Two operations conflict when they belong to different transactions, touch the same item, and at least one is a write. Read-read does not conflict; the order is unobservable. Everything else does.
This gives a workable test. Draw a node per transaction and an edge from T1 to T2 whenever an operation of T1 conflicts with a later operation of T2 on the same item. That edge says T1 must precede T2 in any equivalent serial order. If the resulting graph is acyclic, a valid serial order exists — a topological sort of the graph produces one — and the schedule is conflict serialisable. A cycle means the schedule demands that T1 precede T2 and T2 precede T1, which no serial order can satisfy.
Conflict serialisability is slightly stricter than serialisability in general, since a schedule can accidentally produce a serialisable result through writes that cancel out. Databases use the conflict form because it is checkable from the operations alone, without knowing what the transactions mean.
What two-phase locking does
2PL is a protocol with one rule: a transaction may not acquire any lock after it has released one. Its lifetime therefore has a growing phase in which it only takes locks, and a shrinking phase in which it only releases them, with a single point between them where it holds the maximum set.
That one rule is sufficient to guarantee conflict serialisability, and the argument for why is short. Consider that maximum-holdings point — the lock point — for each transaction. Any conflict between two transactions is mediated by a lock on the item they both touch, so one must have released it before the other acquired it, which orders their lock points. Ordering the transactions by lock point therefore gives a serial order consistent with every conflict, and a consistent order cannot contain a cycle.
Note what this does not say. 2PL never inspects a dependency graph or checks for cycles. It is a local rule each transaction follows independently, and serialisability falls out as a property of the whole system. That is why it is implementable — a cycle check across all in-flight transactions on every operation would not be.
Strict 2PL, and why the extra restriction
Plain 2PL is serialisable but permits a nasty failure. A transaction can release a lock in its shrinking phase, another transaction reads the value it wrote, and then the first transaction aborts. The second has now read data that never officially existed — a dirty read — and to fix it you must abort the second transaction too, and anything that read from it, in a cascade.
Strict 2PL holds all exclusive locks until commit or abort, collapsing the shrinking phase into the moment the transaction ends. Nobody can observe an uncommitted write, so rollback affects only the transaction doing it. Essentially every locking database implements the strict variant, and when a system says "two-phase locking" this is almost always what is meant.
The price is deadlock, and it is not a bug
Because 2PL forbids acquiring after releasing, a transaction that needs a lock held by another must wait rather than release what it holds and retry. Two transactions that need each other's locks wait forever.
This is inherent to the protocol, not a flaw in a particular implementation. You can prevent it by requiring every transaction to acquire all locks up front, or to acquire them in a global order, but both require knowing the full access set in advance — which a query with a WHERE clause does not. So real systems detect instead: they maintain a wait-for graph, look for cycles, and abort a victim, or they simply time out. Either way the application must be prepared to retry, and a transaction that cannot be safely retried is an application-level design problem the database cannot solve for you.
The alternative lineage avoids the conflict rather than managing it. Multiversion concurrency control keeps old versions of rows, so a reader sees a consistent snapshot without taking any lock and never blocks a writer. That removes read-write deadlocks entirely, at the cost of storing versions and of an isolation level that is not quite serialisable — snapshot isolation still permits write skew, where two transactions each read a state, each write something that would have been invalid had it seen the other's write, and neither conflicts directly. Getting from there to genuine serialisability needs extra machinery, which is what PostgreSQL's serialisable isolation level adds on top of its snapshot machinery.
Serialisable means equivalent to some serial order, not to the one you had in mind. Two-phase locking earns that guarantee with a purely local rule, and deadlock is the bill.
Likely follow-ups
- Why does strict two-phase locking hold exclusive locks until commit rather than releasing them earlier?
- Show me a schedule that is serialisable but that two-phase locking would refuse to produce.
- How does snapshot isolation avoid read locks, and what anomaly does it still permit?
- Why do most databases detect deadlocks rather than prevent them?
Related questions
- You are getting a handful of deadlock errors an hour under load. How do you find the cause, and how do you stop them?hardAlso on transactions7 min
- Walk me through the transaction isolation levels and which anomalies each one permits.hardAlso on transactions6 min
- A client times out and retries your POST /payments call. How do you make that endpoint idempotent?hardAlso on transactions5 min
- A worker picks up the job you queued and cannot find the row it was told about. What went wrong?hardAlso on transactions5 min
- A dashboard has been showing the same temperature for two days and nobody noticed. Walk the path and tell me what would have caught it.hardSame kind of round: concept6 min
- Everyone in the business calls it the fax queue, and nothing has been faxed since 2014. Do you keep that name in the code?mediumSame kind of round: concept4 min
- How does your order placement change on a venue that allocates pro rata within a price level instead of first in, first out?hardSame kind of round: concept6 min
- Your A/B test came back not significant. What do you do next?hardSame kind of round: concept4 min