当前位置: 首页 > news >正文

乐观锁悲观锁应用

最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。

十年河东十年河西,莫欺少年穷

学无止境,精益求精

之前我的博客:SQL-乐观锁,悲观锁之于并发详细介绍了乐观锁悲观锁的应用,在此,通过程序来验证:

首先,打开SQLserver,新建一张表:

create table Ticket
(
Id int identity(1,1) primary key,
ticketCount int ,
)

insert into
Ticket values(300)
 
 

我们首先示范悲观锁:如果您还不太明白悲观锁的原理,请查阅我的上篇博客SQL-乐观锁,悲观锁之于并发

悲观锁在使用过程中会锁住要操作的对象,其他用户可以查询该对象的内容,但是不能更新该对象,直至悲观锁释放资源。因此,悲观锁以严格的控制并发,从而使并发零发生。

请在SQLserver中打开两个查询窗口,并输入如下语句:

declare @count as int
begin tran
select @count=ticketCount from Ticket with(updlock)
waitfor delay '00:00:05'
update Ticket set ticketCount=@count-1
commit tran

select * from Ticket

上述语句中的waitfor delay '00:00:05' 代表延迟五秒,用于模拟并发。with(updlock)代表查询时,上了悲观锁,一旦上了悲观锁,其他用户必须等待悲观锁释放后才能访问被锁定的对象,否则,处于等待状态!

快速执行每个窗口中的语句:

执行结果如下:

从上图可以看出,执行二次的结果票数减少2,执行结果正确

要说明的是,在窗口2执行时,必须要等到窗口1执行结束,如果窗体1还在执行,则窗体2处于等待状态。

为了验证悲观锁发生了作用,我们将悲观锁拿掉,然后再快速执行二个窗体中的语句<将票数重置为300,方便我们测试>:

拿掉悲观锁后的语句变更为:

declare @count as int
begin tran
select @count=ticketCount from Ticket
waitfor delay '00:00:05'
update Ticket set ticketCount=@count-1
commit tran

select * from Ticket  

快速执行二个窗体语句,执行结果如下:

由图可知发生了并发,原因是出现了脏读<表中的实际值是299,出了二张票,而票数却只减少1,这显然是错误呀的>。

下面直接贴出乐观锁代码:

修改表结构:添加一列,数据类型为时间戳

Alter Table Ticket Add TimeFlag TimeStamp not null

然后修改事务如下:

declare @count as int
declare @flag as TimeStamp
declare @rowcount As int 
begin tran
select @count=ticketCount,@flag=TimeFlag from Ticket 
waitfor delay '00:00:05'
 
update Ticket set ticketCount=@count-1 where TimeFlag=@flag
set @rowcount=@@ROWCOUNT
if @rowcount>0
print '更新成功'
else
print '更新失败'
commit tran

select * from Ticket

窗体1执行图

 

窗体2执行图

由图可知,窗体2执行失败,是因为当窗体1执行后,时间戳会随着时间变更变为一个新的值,而再次执行时,由于时间戳不同,造成执行失败,从而避免了并发带来的影响。

出了一张票,票数减少1,执行结果正确

为了使系统更加流畅,在窗体2执行失败后,应再次读取数据库并重新执行!

 @陈卧龙的博客

相关文章:

  • mysql 导入sql 报错 2013 2006
  • HDU ACM 题目分类
  • php获取音悦台视频
  • 机器学习如何选择模型 机器学习与数据挖掘区别 深度学习科普
  • mysql 修复指定的数据库
  • Upsource 与Intellij IDEA集成
  • iOS开发中如何将后台返回的时间转换为常见字串
  • 全驱动编程器引脚驱动图
  • 事务的操作
  • [转].net中SessionState相关配置
  • 分享Kali Linux 2016.2第50周镜像文件
  • 静态缓存和动态缓存
  • 编解码-java序列化
  • 富文本控件
  • RAID 详解
  • CentOS从零开始部署Nodejs项目
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • CSS相对定位
  • git 常用命令
  • HTML中设置input等文本框为不可操作
  • input的行数自动增减
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • KMP算法及优化
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Python进阶细节
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 警报:线上事故之CountDownLatch的威力
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 实习面试笔记
  • 实战|智能家居行业移动应用性能分析
  • 网页视频流m3u8/ts视频下载
  • 小李飞刀:SQL题目刷起来!
  • 再谈express与koa的对比
  • Java总结 - String - 这篇请使劲喷我
  • 阿里云移动端播放器高级功能介绍
  • 数据库巡检项
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #、%和$符号在OGNL表达式中经常出现
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (二)Linux——Linux常用指令
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (欧拉)openEuler系统添加网卡文件配置流程、(欧拉)openEuler系统手动配置ipv6地址流程、(欧拉)openEuler系统网络管理说明
  • ./和../以及/和~之间的区别
  • .NET Framework 4.6.2改进了WPF和安全性
  • .Net Memory Profiler的使用举例
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .netcore 6.0/7.0项目迁移至.netcore 8.0 注意事项
  • .NET企业级应用架构设计系列之结尾篇
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • @Autowired @Resource @Qualifier的区别
  • [ NOI 2001 ] 食物链
  • []FET-430SIM508 研究日志 11.3.31
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下