18人参与 • 2026-08-02 • 网络协议
事务对数据对象加锁时,需要遵循某些规则:
不同阶段加锁,加锁不同以及释放锁的时间形成了不同的封锁协议,不同的封锁协议所能达到的系统一致性级别也不同
| 事务a | 事务b |
|---|---|
| begin | |
| update user set age = 18 where id = 5 | begin |
| update user set age = 20 where id = 5 | |
| commit | |
| commit |
| 事务a | 事务b |
|---|---|
| begin | |
| select age from user where id = 5 # age为18 | begin |
| update user set age = 20 where id = 5 | |
| commit | |
| select age from user where id = 5 # age为20 | |
| commit |
| 事务a | 事务b |
|---|---|
| begin | |
| select age from user where id = 5 # age为18 | begin |
| update user set age = 20 where id = 5 | |
| select age from user where id = 5 # age为20 | |
| commit | |
| commit |
保证事务的隔离性,数据的一致性
事务需要对数据做第一次写操作前(例如:insert,update)需要加写锁,一直到事务结束才能释放锁,读操作不要求加锁
| 事务a | 事务b |
|---|---|
| 执行对user表的update操作 | |
| 获取写锁 | |
| 获取成功,加锁 | |
| 执行对user表的update操作 | |
| 获取写锁 | |
| 获取失败,等待 | |
| 执行sql后commit | 等待 |
| 释放锁 | 等待 |
| 获取写锁成功,加锁 | |
| 执行sql后commit | |
| 释放锁 |
在此协议中,写操作需要加锁,可以解决并发调度中丢失修改问题,但是由于读操作不需要加锁,所以任何阶段都有可能读取到未提交的数据
在一级封锁协议基础上,事务对数据做读操作,需要加读锁,读后任意时刻可以释放
| 事务a | 事务b |
|---|---|
| 执行对user表的update操作 | |
| 获取写锁 | |
| 获取成功,加锁 | |
| 执行对user表的select操作 | |
| 获取读锁 | |
| 获取失败,等待 | |
| 执行sql后commit | 等待 |
| 释放锁 | 等待 |
| 获取读锁成功,加锁 | |
| 执行sql | |
| 释放锁 | |
| commit |
| 事务a | 事务b |
|---|---|
| begin | |
| 获取读锁 | |
| 获取成功 | |
| s(user) | |
| begin | |
| 获取读锁 | |
| 获取失败,等待 | |
| select * from user | 等待 |
| 释放锁unlock(user) | 等待 |
| commit | 获取读锁成功 |
| s(user) | |
| select * from user where id = 5 | |
| 释放锁unlock(user) | |
| 获取写锁 | |
| 获取成功 | |
| x(user) | |
| insert into user values(5, “xiaoming”) | |
| commit | |
| 释放锁unlock(user) |
此协议在读操作前加锁,因为同一时刻锁不能共同持有,那么就读取不到未提交的数据,可以解决脏读问题,但是锁在事务提交前释放,可能会造成第二次读取时数据与第一次不一致
在一级封锁协议基础上,若事务对数据做第一次读操作,要求对其加读锁,事务结束后才能释放锁
| 事务a | 事务b |
|---|---|
| 执行对user表的update操作 | |
| 获取写锁 | |
| 获取成功,加锁 | |
| 执行对user表的select操作 | |
| 获取读锁 | |
| 获取失败,等待 | |
| 执行sql后commit | 等待 |
| 释放锁 | 等待 |
| 获取读锁成功,加锁 | |
| 执行sql | |
| commit | |
| 释放锁 |
此协议只在第一次读取的时候加锁,同一个事务中多次读取操作不需要重新获取锁,且锁需要在commit后才能释放,可以解决不可重复读的问题
| 封锁协议 | 写锁 | 读锁 | 不丢失修改 | 不读脏数据 | 可重复读 |
|---|---|---|---|---|---|
| 一级 | 事务全程加锁 | 不加 | √ | ||
| 二级 | 事务全程加锁 | 读前加,加后随时释放 | √ | √ | |
| 三级 | 事务全程加锁 | 事务全程加锁 | √ | √ | √ |
two-phase locking(2pl),指在事务中需要包含两个阶段,一个是加锁阶段,一个是解锁阶段。在加锁阶段,事务需要获取到所需的锁,期间不可以释放任何锁;在解锁阶段,事务释放获取到的所有锁,且后面不可以再获取锁。两段锁协议是为了保证并发调度的可串行化
| 事务a | 阶段 |
|---|---|
| begin | |
| select * from user | 加锁阶段:获取s(user) |
| update user set age = 18 where id = 5 | 加锁阶段:获取x(user) |
| commit | |
| 解锁阶段:释放s(user)、x(user) |
到此这篇关于数据库封锁协议和两段锁协议的文章就介绍到这了,更多相关数据库封锁协议和两段锁协内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论