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

SQL-乐观锁,悲观锁之于并发

为什么需要锁(并发控制)?
  在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题。
典型的冲突有:
  • 丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失。例如:用户A把值从6改为2,用户B把值从2改为6,则用户A丢失了他的更新。
  • 脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取。例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6。
为了解决这些并发带来的问题。 我们需要引入并发控制机制。
 
并发控制机制
  悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。[1]
  乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。[1] 乐观锁不能解决脏读的问题。
 
悲观锁应用
需要使用数据库的锁机制,比如SQL SERVER 的TABLOCKX(排它表锁) 此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。
Begin Tran
select top 1 @TrainNo=T_NO
from Train_ticket with (UPDLOCK) where S_Flag=0
 
update Train_ticket
set T_Name=user,
T_Time=getdate(),
S_Flag=1
where T_NO=@TrainNo
commit
我们在查询的时候使用了with (UPDLOCK)选项,在查询记录的时候我们就对记录加上了更新锁,表示我们即将对此记录进行更新. 注意更新锁和共享锁是不冲突的,也就是其他用户还可以查询此表的内容,但是和更新锁和排它锁是冲突的.所以其他的更新用户就会阻塞.
 
在此:举个简单的例子来说明悲观锁的应用,我们以SQLServer为例进行说明:
假如两个线程同时修改数据库同一条记录,就会导致后一条记录覆盖前一条,从而引发一些问题。
例如:
  一个售票系统有一个余票数,客户端每调用一次出票方法,余票数就减一。
情景:
  总共300张票,假设两个售票点,恰好在同一时间出票,它们做的操作都是先查询余票数,然后减一。
一般的sql语句:
declare @num int;
begin tran
select @num = [Num] FROM [Test8].[dbo].[Table_1] with(nolock) where ID = 1
WAITFOR DELAY '00:00:05' --模拟并发,估计延迟5秒
update [Test8].[dbo].[Table_1] set Num =@num -1
 
commit tran
 
 
 
同时执行两个窗口执行这个脚本,最终更新结果有误
 
declare @num int;
begin tran
select @num = [Num] FROM [Test8].[dbo].[Table_1] with(updlock) where ID = 1
WAITFOR DELAY '00:00:05' --模拟并发,估计延迟5秒
update [Test8].[dbo].[Table_1] set Num =@num -1
 
commit tran
 
SELECT TOP 1000 [ID]
,[Num]
,[Title]
FROM [Test8].[dbo].[Table_1]
 
在A窗口执行的时候,B窗口会等待A执行完毕才执行
 
如果这个售票系统并发太高(例如:春节售票,十月一国庆售票等买票人员并发操作很高),我们采用上述的悲观锁方案就会是系统性能大大降低。譬如:售票员A锁定了这个操作,售票员A在处理这个业务的过程中,又去喝了杯咖啡,在此期间,其他业务员是无法进行订票的,所以...
乐观锁解决方案:
新增一列 Timestamp
alter table Table_1 ADD timesFlag timestamp not null
 
declare @num int;
declare @flag timestamp;
declare @rowCount int;
begin tran
select @num = Num,@flag = timesFlag FROM [Test8].[dbo].[Table_1]
waitfor delay '00:00:05'
update [Test8].[dbo].[Table_1] set Num = @num-1 where timesFlag = @flag
set @rowCount = @@ROWCOUNT
 
commit tran
if(@rowcount>0)
print 'OK'
else
print 'Error'
两个窗口同时执行该命令,一个输出 OK,一个输出Error
这便是乐观锁的解决方案,可以解决并发带来的数据错误问题,但不保证每一次调用更新都成功,可能会返回'更新失败'
 
悲观锁和乐观锁
  悲观锁一定成功,但在并发量特别大的时候会造成很长堵塞甚至超时,仅适合小并发的情况。
  乐观锁不一定每次都修改成功,但能充分利用系统的并发处理机制,在大并发量的时候效率要高很多。

 

转载于:https://www.cnblogs.com/wangshitou/p/10613162.html

相关文章:

  • iOS:“Invalid top-level type in JSON write”引起程序闪退
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • 真正的反演笔记
  • 作为面试官的一点点感悟,谈谈技术人的成长之路
  • 阿里程序员工作小技巧:理解CPU分支预测,提高代码效率
  • Ubuntu18.04配置双网卡、双路由
  • 刚刚,阿里发布AI谣言粉碎机,识别准确率达81%
  • 如何通过StackStorm自动支持2万多台服务器
  • 流动的SVG线条
  • Spring框架IOC和AOP的实现原理(概念)
  • 使用GlobalSSH加速Ansible海外部署效率
  • gulp的使用方法
  • npm更新升级
  • 微信自动跳转外部浏览器打开网页或下载APP的技术源码,可以避免分享链接被微信拦截...
  • 微信小程序中使用emoji表情相关说明
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【5+】跨webview多页面 触发事件(二)
  • Java读取Properties文件的六种方法
  • Java多线程(4):使用线程池执行定时任务
  • Joomla 2.x, 3.x useful code cheatsheet
  • Leetcode 27 Remove Element
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • Markdown 语法简单说明
  • Otto开发初探——微服务依赖管理新利器
  • React Native移动开发实战-3-实现页面间的数据传递
  • tweak 支持第三方库
  • Vue2.x学习三:事件处理生命周期钩子
  • 测试如何在敏捷团队中工作?
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 翻译--Thinking in React
  • 分享几个不错的工具
  • 高度不固定时垂直居中
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 如何利用MongoDB打造TOP榜小程序
  • 算法之不定期更新(一)(2018-04-12)
  • 译米田引理
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (C++17) std算法之执行策略 execution
  • (libusb) usb口自动刷新
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (理论篇)httpmoudle和httphandler一览
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (转)fock函数详解
  • (转)VC++中ondraw在什么时候调用的
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】
  • .htaccess配置常用技巧
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core日志内容详解,详解不同日志级别的区别和有关日志记录的实用工具和第三方库详解与示例
  • .NET Core实战项目之CMS 第十二章 开发篇-Dapper封装CURD及仓储代码生成器实现