注意两阶段锁(Two-phase locking,2PL)需要和两阶段提交(Two-phase commit)区别开来。
两阶段锁(Two-phase locking,2PL)用于实现serializability;而两阶段提交(Two-phase commit)是实现分布式事务的一种方式。
两阶段锁(Two-phase locking,2PL)
In databases and transaction processing, two-phase locking (2PL) is a concurrency control method that guarantees serializability.
It is also the name of the resulting set of database transaction schedules (histories). The protocol utilizes locks, applied by a transaction to data, which may block (interpreted as signals to stop) other transactions from accessing the same data during the transaction’s life.
By the 2PL protocol, locks are applied and removed in two phases:
-
Expanding phase: locks are acquired and no locks are released.
-
Shrinking phase: locks are released and no locks are acquired.
Two types of locks are utilized by the basic protocol: Shared and Exclusive locks.
2PL uses two types of locks: shared and exclusive locks.
- A shared lock (read lock) can be acquired by multiple transactions, but it prevents any transaction from acquiring an exclusive lock.
- An exclusive lock (write lock) prevents both shared and exclusive locks to be acquired until the acquired exclusive lock is released (during transaction commit or rollback).
In Two-Phase Locking, locks can be acquired either at the row-level, to prevent lost updates, read and write skews, or they can be acquired for a range of rows so that phantom reads are prevented.
On the other hand, this locking protocol divides the execution phase of a transaction into three parts:
- the first part, when the transaction starts executing, it seeks permission for the locks it requires
- the second part is where the transaction acquires all the locks. As soon as the transaction releases its first lock, the third phase starts.
- the third phase, the transaction cannot demand any new locks; it only releases the acquired locks.
这意味着,不管同一个事务内需要在多少个数据项上加锁,所有的加锁操作都只能在加锁阶段(增长阶段)完成。在这个阶段内,不允许对已经加锁的数据项进行解锁操作。同时,在加锁完成后,也只能在解锁阶段(缩减阶段)对所有数据项进行解锁。当解锁阶段结束后,所有持有的锁都已经被释放。
The common interactions between these lock types are defined by blocking behavior as follows:
- An existing write-lock on a database object blocks an intended write upon the same object (already requested/issued) by another transaction by blocking a respective write-lock from being acquired by the other transaction. The second write-lock will be acquired and the requested write of the object will take place (materialize) after the existing write-lock is released.
- A write-lock blocks an intended (already requested/issued) read by another transaction by blocking the respective read-lock .
- A read-lock blocks an intended write by another transaction by blocking the respective write-lock.
- A read-lock does not block an intended read by another transaction. The respective read-lock for the intended read is acquired (shared with the previous read) immediately after the intended read is requested, and then the intended read itself takes place.
Lock type | read-lock | write-lock |
---|---|---|
read-lock | ✔ | X |
write-lock | X | X |
- ✔ indicates compatibility
- X indicates incompatibility, i.e, a case when a lock of the first type (in left column) on an object blocks a lock of the second type (in top row) from being acquired on the same object (by another transaction). An object typically has a queue of waiting requested (by transactions) operations with respective locks. The first blocked lock for operation in the queue is acquired as soon as the existing blocking lock is removed from the object, and then its respective operation is executed. If a lock for operation in the queue is not blocked by any existing lock (existence of multiple compatible locks on a same object is possible concurrently), it is acquired immediately.
为什么需要两阶段加锁
两阶段加锁是一种**并发控制(Concurrency Control)的一种手段,除此之外,也可以通过多版本并发控制(Multiversion Concurrency Control)**实现。
引入两阶段加锁是为了在保证事务的隔离性(即多个事务在并发的情况下等同于串行的执行)去前提下,尽可能的提高事务的并发度。
为了提高并发度,才对锁进行分类,分出共享锁(读锁)和排它锁(写锁),因这两种类型的锁,又产生加两种锁共四种事务之间受影响的情况:
Strict two-phase locking
The first phase of Strict-2PL is same as 2PL. After acquiring all the locks in the first phase, the transaction continues to execute normally.
But in contrast to 2PL, Strict-2PL does not release a lock after using it. Strict-2PL holds all the locks until the commit point and releases all the locks at a time.
Two-phase locking and its special cases
Two-phase locking
According to the two-phase locking protocol, a transaction handles its locks in two distinct, consecutive phases during the transaction’s execution:
- Expanding phase (aka Growing phase): locks are acquired and no locks are released (the number of locks can only increase).
- Shrinking phase (aka Contracting phase): locks are released and no locks are acquired.
The two phase locking rules can be summarized as: never acquire a lock after a lock has been released. The serializability property is guaranteed for a schedule with transactions that obey this rule.
Typically, without explicit knowledge in a transaction on end of phase 1, it is safely determined only when a transaction has completed processing and requested commit. In this case, all the locks can be released at once (phase 2).
Conservative two-phase locking
The difference between 2PL and C2PL is that C2PL’s transactions obtain all the locks they need before the transactions begin. This is to ensure that a transaction that already holds some locks will not block waiting for other locks. Conservative 2PL prevents deadlocks.
Strict two-phase locking
To comply with the S2PL protocol, a transaction needs to comply with 2PL, and release its write (exclusive) locks only after it has ended, i.e., being either committed or aborted. On the other hand, read (shared) locks are released regularly during phase 2. This protocol is not appropriate in B-trees because it causes Bottleneck (while B-trees always starts searching from the parent root).[citation needed]
Strong strict two-phase locking
Implementation of two-phase locking
Performance of two-phase locking
Reference
- https://en.wikipedia.org/wiki/Two-phase_locking#Conservative_two-phase_locking
- Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems
- https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html