乐观锁--悲观锁
测试案例
id | name | money |
---|---|---|
1 | 小明 | 1000 |
小明的账户上有1000 元 ,现在有两个线程同时往他账户上加钱。
1.A 线程准备往小明的账户上加100, 1, 读取到小明 有 1000 元, 1000 + 100 事务未提交;
2.B 线程准备往小明的账户上加200, 1, 读取到小明 有 1000 元 ,1000 + 200 事务未提交;
3.A 线程提交事务 小明账户余额变成1100, 但这时B 线程还不知道小明账户余额变成1100了;
id | name | money |
---|---|---|
1 | 小明 | 1100 |
4.B 线程提交事务 小明账户余额变成1200。
id | name | money |
---|---|---|
1 | 小明 | 1200 |
A 线程的更新丢失 本来余额应该是1300,结果余额变成1200
加锁的目的在于保障 一个线程修改数据时这个数据没有被其他线程改过。
一、何为乐观锁与悲观锁
乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
二、悲观锁
介绍
再事务的基础上,悲观锁 适合短事务(长事务导致其它事务一直被阻塞,影响系统性能),查少该多。
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁,保证了数据安全。(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
使用
悲观锁的概念,他觉有人会修改我读的数据。那我就再查的时候,对数据进行锁定。
在数据库中:for update
在Django中:select_for_update()
原生的sql:
1 开启事务
2 查询的时候加锁 ---》 select * from user where id =1 for update
3 结束事务锁被释放
django中:
1 开启事务
2 在查询的时候 ---》 user.objects.select_for_update().flilter(id=1).first()
3 事务结束锁被释放
三、乐观锁
介绍
乐观锁的本质不是,而是一种思想。他是通过代码逻辑来实现锁的。在修改的那一刻判断这个数据有没有被修改。乐观锁适合查多改少。
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁。但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。乐观锁适用于多读的应用类型,这样可以提高吞吐量。增加并发量
使用
再事务的基础上:先拿到age数据,在修改的时候再次判断age是否一样。(代码实现)
乐观锁的本质不是锁。他是通过代码逻辑来实现锁的。他觉的别人不会修改的他的数据。他认为读数据不会被别人修改。最后再update时,再where条件中添加,之前查出来的数据。以保证数据的安全性
# 方法:先拿到age数据,在修改的时候再次判断age是否一样。(代码实现)
1 开启事务
2 拆线呢的时候不做任何操作。data = user.objects.flilter(id=1).first()将这个数据中的age在原来的基础上+1
3 在修在数据的时候。user.objects.filter(id=1,age=data.age).updata(age=data.age+1)从而在我查询到我修改的时候,没有人改动过
4 如果3中的影响行数为0,证明数据被人修改。循环再次执行。如果为1,证明数据没人动过,修改成功
# 如果是可重复读,上面的乐观锁无效,必须改成read committed
sql:
之前amount=100,现在修改10
UPDATE order_bill set amount = 10 WHERE id = 2810 and amount=100 returning id
如果没有id返回,证明在此期间被修改过了,重新执行事物
四、两种锁的使用场景
1.乐观锁 适合查多改少,经常被并发修改的数据可能老是出现版本不一致导致有的线程操作常常失败。
2.悲观锁 适合短事务(长事务导致其它事务一直被阻塞,影响系统性能),查少该多。
五、总结
并没有什么乐观锁比 悲观锁好,它们所适应的是不用的场景。你可以根据你的业务选择合适的锁。
选择了IT,必定终身学习
posted @ Jeff的技术栈 阅读 (9999+) 评论 (99) 点赞(99) 编辑 MD 收藏
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】博客园携手 AI 驱动开发工具商 Chat2DB 推出联合终身会员
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 依赖注入中的 Captive Dependency
· .NET Core 对象分配(Alloc)底层原理浅谈
· 聊一聊 C#异步 任务延续的三种底层玩法
· 敏捷开发:如何高效开每日站会
· 为什么 .NET8线程池 容易引发线程饥饿
· 一个适用于 .NET 的开源整洁架构项目模板
· 【开源】C#上位机必备高效数据转换助手
· .NET 9.0 使用 Vulkan API 编写跨平台图形应用
· MyBatis中的 10 个宝藏技巧!
· [.NET] 使用客户端缓存提高API性能