- 数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和数据的一致性。
- 乐观锁(乐观并发控制)和 悲观锁(悲观并发控制)是并发控制主要采用的技术手段
锁名称 |
并发控制 |
说明 |
乐观锁 (Optimistic Lock) |
乐观并发控制 (Optimistic Concurrency Control) |
假设并发冲突的发生比较少见,不显式地对数据加锁,通过在数据上添加版本号或时间戳等机制进行校验,多个事务可以同时访问和操作数据。
事务执行时,仅当校验发现冲突时,事务回滚或重试 |
悲观锁 (Pessimistic Lock)
|
悲观并发控制 (Pessimistic Concurrency Control) |
假设在事务执行过程中会发生并发冲突,在事务访问数据之前,将数据上锁,阻塞其他事务对其进行修改或访问。
事务开始时就获取锁,并在整个事务执行过程中持有锁,直到事务完成后才释放锁 |
- 乐观锁(Optimistic Lock)在事务更新数据时,它会首先读取数据并记录版本信息,然后在写回数据时,检查版本信息是否发生变化,以判断是否有其他事务对数据进行了修改。如果版本一致,则顺利提交更新,如果版本冲突,则需要进行冲突解决,例如回滚事务、重试或放弃更新操作
- 悲观锁(Pessimistic Lock)又可分为排他锁(Exclusive Lock)和共享锁(Share Lock)
锁类型 |
名称 |
简称 |
说明 |
Exclusive Lock |
排他锁 互斥锁 独占锁 写锁 |
X 锁 |
事务进行写操作,数据在没有加锁的情况下,事务可以对其加排他锁,其他事务不能再加任何锁
其他事务不能对数据进行修改和读取操作,用于保证并发访问时只能进行修改操作 |
Share Lock |
共享锁 读锁 |
S 锁 |
事务进行读操作,事务对数据加共享锁后,其他事务就不能对其加共享锁以外的锁,多个事务可以同时获取共享锁
其他事务不能对数据进行修改操作,但可以进行读取操作,用于保证并发访问时只能进行读取操作 |
注
- 悲观锁通常用于写比较多的情况下(多写场景,竞争激烈),通过加锁保证数据的一致性,这样可以避免频繁失败和重试影响性能。
- 乐观锁通常于写较少的情况下(多读场景,竞争较少),通过检查防止数据冲突,以避免频繁加锁影响性能,提高并发性能
两段锁协议
- 两段锁协议(Two-Phase Locking Protocol,2PL)是一种数据库事务并发控制算法,通过在事务执行过程中强制所有访问数据的操作按照特定顺序进行加锁和解锁,保证事务的串行化执行
- 两段锁协议是指在对任何数据进行读、写操作之前,事务首先要申请并获得对该数据的封锁,当释放一个封锁之后,事务不再申请和获得任何其他封锁
- 在两段锁协议下,整个事务分为两个阶段,前一个阶段为加锁,后一个阶段为解锁
阶段 |
别名 |
说明 |
加锁 |
扩展阶段 |
在加锁阶段,事务只能加锁,不能解锁
事务会先获取需要访问的数据的共享锁或排它锁,当获取排它锁后,事务可以继续获取共享锁,但是不能获取排它锁 |
解锁 |
收缩阶段 |
当事务释放了一个锁以后,事务进入解锁阶段,在解锁阶段,事务只能解锁,不能再加锁
事务会释放所有持有的锁,在释放所有锁之前,事务不能获取任何新的锁 |
- 两段锁协议保证了事务在提交前所持有的锁不会被释放,其他事务不能访问相同的数据,从而避免了数据冲突和不一致性。
注
- 如果并发执行的所有事务都遵循两段锁协议,那么对这些事务的任何并发调度都是可串行化的
- 两段锁协议只能保证事务的可串行调度,而不能保证并行可调度。如果多个事务并发地访问同一组数据,并且没有按照特定的顺序获取锁,那么就有可能会产生死锁。
封锁协议
- 在使用 排他锁(Exclusive Lock)和 共享锁(Share Lock)对数据对象加锁时,还需要约定一些规则 ,例如何时申请 排他锁(Exclusive Lock)或 共享锁(Share Lock)、持锁时间、何时释放等,这些规则为封锁协议(Locking Protocol)。
- 不同的封锁协议,在不同的程度上为并发操作的正确调度提供一定的保证。根据不同的规则,分为以下三种封锁协议
协议 |
针对问题 |
说明 |
一级封锁协议 |
更新丢失 |
任一事务在修改数据前,必须对其加上排他锁(X锁),直到事务结束后才释放。
事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK) |
二级封锁协议 |
更新丢失 脏读 |
在一级封锁协议的基础上,任一事务在读取某数据前,必须对其加上共享锁(S锁),读取完毕后释放共享锁(S锁) |
三级封锁协议 |
更新丢失 脏读 不可重复读 |
在一级封锁协议的基础上,任一事务在读取某数据前,必须对其加上共享锁(S锁),事务结束后才释放锁共享锁(S锁) |