Each transaction acquires all its locks before releasing any — a growing then shrinking phase — which guarantees a serializable schedule.
Two-phase locking keeps concurrent transactions safe by making each one lock the data it touches before using it. A shared lock is a read lock — many transactions may hold one on the same item at once. An exclusive lock is a write lock — only one holder, blocking every other read and write of that item. The 'two-phase' rule is what turns locking into a *correctness guarantee*.
Because no transaction gives up a lock while it still intends to take more, conflicting transactions are forced to wait their turn. That discipline is enough to guarantee a conflict-serializable schedule.
T1: lock-X(A) read/write A -- growing
lock-X(B) -- growing (this is the LOCK POINT)
write B
unlock(A) -- shrinking
unlock(B) -- shrinking
|---- growing ----|---- shrinking ----|2PL guarantees serializability but *not* liveness. A deadlock arises when two transactions each wait for a lock the other holds:
T1: lock-X(A) ... wants lock-X(B) -- blocked, T2 holds B
T2: lock-X(B) ... wants lock-X(A) -- blocked, T1 holds A
Each waits for the other => circular wait => DEADLOCKStrict 2PL strengthens the rule: hold *every* exclusive lock until the transaction commits or aborts, collapsing the shrinking phase to the very end. This prevents cascading aborts — no other transaction can read a value that a not-yet-committed transaction might still roll back. It does not, however, remove the deadlock risk.