离线并发模式
乐观离线锁
使用冲突检测与事务回滚来防止事务冲突
- 验证一个提交的修改不会与其他修改发生冲突
通过版本号来实现
sequenceDiagram
session1 ->> 数据库: 获取用户1
数据库 ->> session1: 返回用户1 版本号1
session1 ->> session1: 修改用户1
session2 ->> 数据库: 获取用户1
数据库 ->> session2: 返回用户1 版本号1
session2 ->> session2: 修改用户1
session2 ->> 数据库: 提交 用户1 版本号 1
数据库 ->> session2: 修改用户1成功 版本号2
session1 ->> 数据库: 提交 用户1 版本号 1
数据库 -->> session1: 失败 版本号不一致
UPDATE users WHERE id = 1 AND version = 1;
这种乐观的离线锁是针对具体领域的解决方案
悲观离线锁
每次只允许一个会话访问数据
sequenceDiagram
par 事务边界
session1 ->> 数据库: 获取用户1
数据库 ->> session1: 返回用户1
end
par 事务边界
session2 ->> 数据库: 获取用户1
数据库 -->> session2: 失败 用户1被锁住
end
session1 ->> session1: 修改用户1
尽可能早检测出冲突
锁的类型:
- 独占写锁
- 当编辑数据时,需要对数据加锁
- 独占读锁
- 当读取数据时,需要加锁
- 读写锁
- 读锁与写锁是互斥的
- 可以进行并发地读
锁管理对象
如何管理锁与锁的持有者?
实现尽可能简单,使用散列表映射锁及锁的持有者
粗粒度锁
- 获取与释放锁的代价很小
用锁锁住一组相关的对象,DDD中的聚合根就可以代表是锁的入口点
隐含锁
将加锁的任务交给父类或者框架,避免繁琐的客户编程加锁释放锁导致出现的问题