Two-Phase Commit (2PC)
2PC coordinates an atomic transaction across multiple participants using a prepare phase and a commit phase.
What is two-phase commit (2PC)?
Two-Phase Commit (2PC) is a distributed protocol that ensures an atomic transaction across multiple participants (databases, services). Either all participants commit the transaction or all abort - no partial commits.
The Protocol
There are two roles: a Coordinator (the node initiating the transaction) and Participants (the nodes that will commit or abort).
Phase 1: Prepare
- Coordinator sends
PREPAREto all participants - Each participant:
- Locks all resources needed for the transaction
- Writes the transaction to its WAL (durable even if it crashes)
- Responds
YES(ready to commit) orNO(cannot commit)
- Participants that reply
YESare now in a prepared state - they've promised to commit if asked
Phase 2: Commit or Abort
If coordinator receives YES from all participants:
- Sends
COMMITto all participants - Participants commit, release locks, acknowledge
If coordinator receives any NO (or timeout):
- Sends
ABORTto all participants - Participants rollback, release locks
The Blocking Problem
2PC's fundamental flaw: it blocks when the coordinator fails.
Scenario:
- All participants respond
YES(prepared state, locks held) - Coordinator crashes before sending
COMMITorABORT - Participants are stuck: they promised to commit but can't proceed without the coordinator's decision
- They hold their locks - blocking other transactions
Participants cannot unilaterally commit (might violate atomicity) or abort (coordinator might have sent COMMIT to some participants before crashing).
Resolution: a new coordinator must be elected and query participants' state, or wait for the original coordinator to recover.
Three-Phase Commit (3PC)
3PC adds a PRE-COMMIT phase between Prepare and Commit to reduce the blocking window:
PREPARE-> participants respondYESPRE-COMMIT-> coordinator confirms all said yes; participants acknowledgeCOMMIT-> all commit
If coordinator fails after pre-commit, participants know all others said YES and can safely commit. But 3PC is more complex and still has edge cases in network partitions - not widely used in practice.
XA Transactions
XA is the standard specification for distributed transactions using 2PC. Most relational databases support XA: PostgreSQL, MySQL, Oracle. Java applications use JTA (Java Transaction API) to coordinate XA transactions.
XA works across heterogeneous systems (different databases in the same transaction) but carries all 2PC limitations.
2PC vs Saga Pattern
| 2PC | Saga | |
|---|---|---|
| Atomicity | True ACID across participants | Eventual consistency via compensation |
| Blocking | Yes (coordinator failure) | No |
| Availability | Lower (locks held) | Higher |
| Complexity | Lower (single protocol) | Higher (compensating transactions) |
| Use when | Same-org databases, low latency | Microservices, high availability needed |
When to Use 2PC
✅ All participants are within your control and on low-latency links ✅ True atomicity is required (financial ledger, inventory) ✅ Failure scenarios are rare and acceptable downtime is tolerable
❌ Microservices across organisational boundaries ❌ High-availability requirements (blocking is unacceptable) ❌ High-latency links between participants
Interview Angle
For "how do you handle distributed transactions?", explain both 2PC and Saga and their tradeoffs. 2PC gives true atomicity but blocks on coordinator failure. Saga gives high availability but requires compensating transactions and accepts eventual consistency. For microservices -> prefer Saga. For same-database multi-table -> use native transactions. 2PC is the middle ground most people never actually need.