数据库中有表[01_SubjectiveScoreInfo],要实现表中的数据只被查出一次,此表数据量较大,有三四百万数据。表结构也确实不是很合理,无法修改表结构,即使是新增一个字段也会有相当大的修改量。

因之前代码中存在大量的insert into select *的语句,加一个字段什么也不做也会导致整个项目瘫痪,当然我不想去讨论前人的代码质量。

于是乎我加了一个新表[01_SubjectiveScoreInfoFlag]来进行记录取过的记录ID。于是就有了如下的代码:

BEGIN TRAN

                    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

                    INSERT INTO [01_SubjectiveScoreInfoFlag](ID)
SELECT TOP 100 SS.ID
FROM [01_SubjectiveScoreInfo] AS SSINNER JOIN SubjectiveItemInfo AS SI
ON SS.TestCode=SI.TestCode
AND SS.MajorQuestionID=SI.MajorQuestionID
AND SS.MinorQuestionID=SI.MinorQuestionID
WHERE SS.TestCode=''' + @TestCode + '''
AND SI.QuestionGroupCode=''' + @QuestionGroupCode + '''
AND (SI.MinorQuestionCount=0
OR SI.MinorQuestionID>0)
AND NOT EXISTS
(
SELECT TOP 1 1
FROM [01_SubjectiveScoreInfoFlag]
WHERE ID = SS.ID
) COMMIT TRAN

此处用到了事务,并且指定了隔离级别。这个是必须的,我们之前就是没有指定,单线程无论你怎么调用这段代码运行都非常可靠,但多线程模拟并发调用时就出现了非常严重的重复。

上面的代码也并没有解决问题,原因是锁用得不对,多线程直接就出现了死锁现象。因之前对于隔离级别没什么经验,我一度曾经以为这个问题是无解的,直到今天突然被解开了。

按照我自己的理解,是因为锁的级别不够,导致了资源争抢。

就相当于上厕所时,一定要获取完全的排它锁,关好门不让其它人进来;否则如果其它人进来了,虽然他没有占到位子,但他拿走了手纸。你占着位子却没有手纸,他拿着手纸却没有位子,双方互不相让,谁也无法完成上厕所的事务,相持不下,进而导致死锁。这时就需要厕所管理出面,要么强制让你让出位子走人,不管理你擦没擦屁股;要么抢来手纸赶走他,任他拉到裤子上。

于是乎就有了下面的代码:

BEGIN TRAN

                    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

                    INSERT INTO ['+@CourseID+'_SubjectiveScoreInfoFlag](ID)
SELECT TOP 100 SS.ID
FROM ['+@CourseID+'_SubjectiveScoreInfo] AS SS WITH(UPDLOCK)
INNER JOIN SubjectiveItemInfo AS SI WITH(UPDLOCK)
ON SS.TestCode=SI.TestCode
AND SS.MajorQuestionID=SI.MajorQuestionID
AND SS.MinorQuestionID=SI.MinorQuestionID
WHERE SS.TestCode=''' + @TestCode + '''
AND SI.QuestionGroupCode=''' + @QuestionGroupCode + '''
AND (SI.MinorQuestionCount=0
OR SI.MinorQuestionID>0)
AND NOT EXISTS
(
SELECT TOP 1 1
FROM ['+@CourseID+'_SubjectiveScoreInfoFlag] WITH(UPDLOCK)
WHERE ID = SS.ID
) COMMIT TRAN

UPLOCK是排它锁,这样就没有死锁了。

SQL Server 幻读 的真实案例的更多相关文章

  1. SQL Server一个特殊的阻塞案例分析2

    最近发现一个非常奇怪的阻塞问题,如下截图所示(来自监控工具DPA),会话583被会话1036阻塞,而且阻塞发生在tempdb,被阻塞的SQL如下截图所示,会话等待类型为LCK_M_S 因为DPA工具不 ...

  2. 初谈SQL Server逻辑读、物理读、预读

    前言 本文涉及的内容均不是原创,是记录自己在学习IO.执行计划的过程中学习其他大牛的博客和心得并记录下来,之所以想写下来是为了记录自己在追溯的过程遇到的几个问题,并把这些问题弄清楚. 本章最后已贴出原 ...

  3. SQL Server逻辑读、预读和物理读

    SQL Server数据存储的形式 预读:用估计信息,去硬盘读取数据到缓存.预读100次,也就是估计将要从硬盘中读取了100页数据到缓存. 物理读:查询计划生成好以后,如果缓存缺少所需要的数据,让缓存 ...

  4. 初谈SQL Server逻辑读、物理读、预读【转】

    前言 本文涉及的内容均不是原创,是记录自己在学习IO.执行计划的过程中学习其他大牛的博客和心得并记录下来,之所以想写下来是为了记录自己在追溯的过程遇到的几个问题,并把这些问题弄清楚. 本章最后已贴出原 ...

  5. SQL Server服务没有自动启动原因案例分析

    这个案例是前两天出现的,一直没有时间总结,25号凌晨4点去处理数据库的故障问题.远程连上公司的局域网,psping检查发现服务器的1433端口不通,数据库连接不上,但是主机又能ping通,登录服务器检 ...

  6. SQL Server数据库邮件发送异常案例

      最近遇到两起关于SQL Server数据库邮件发送异常的案例,这些问题也有点意思,顺便记录一下.方便以后遇到类似问题的人参考,不要被这些问题弄得抓狂! 案例1:我们一台数据库服务器突然发送邮件都不 ...

  7. SQL Server 一致性读

    我们在Oracle和MySQL数据库中已经对一致性读的概念比较熟悉了,但是在SQL Server中却鲜少提及,但SQL Server自2005版本以来其实也实现了一致性读,几乎所有关系型数据库产品的一 ...

  8. 应对黑客攻击SQL SERVER数据库中的一个案例

    最近发现挂在网上server不知怎的,重新启动,那server现在主要是开始IIS服务,SQL SERVER 服务. 远程登录.发现系统响应十分缓慢.一个明显的停滞感,打开任务管理器,CPU在基本用法 ...

  9. SQL Server作业报错特殊案例

    一个作业报错,报错信息如下,从错误信息根本看不出为什么出错,手工运行作业又成功了.一时不清楚什么原因导致作业出错. Message Executed as user: NT SERVICE\SQLSE ...

随机推荐

  1. nodejs创建文件

    var fs = require('fs'); fs.writeFile(path + "test.txt", "hello world!", function ...

  2. CentOS7.x系统中使用Docker时,在存储方面需要注意的问题

    简述: 1.Docker 1.12.6/v17.03文档中CentOS7系统下安装时,明确说明,用于生产时,必须使用devicemapper驱动的direct-lvm模式,需要我们提前准备好块设备,以 ...

  3. 使用echarts时option可以复用的方法

    其实复用option很简单,在所要展示的图形在其他需求大致一致时,即可写一个option然后设置不同的地方就好了,坐标轴.series等都可以设置,具体代码如下: var barLeft = echa ...

  4. UGUI之导入图片之前自动设置图片打包的 tag

    之前一直在用的是NGUI,最近不知怎么突然兴趣来潮,想学习一下UGUI,毕竟,现在纵观Unity的市场,完全是UGUI的天下,NGUI已经渐渐退隐江湖,哈哈哈... 先来记录下,在图片资源导入到Uni ...

  5. 《SQL 基础教程》第二章:查询基础

    这一章的结构如下: SELECT 语句基础 算术运算符和比较运算符 逻辑运算符 SELECT 语句可用于查询数据,并且可以设定条件来查询具有特定值的记录.条件的设定就需要算数运算符.比较运算符和逻辑运 ...

  6. Luffy之课程详情页

    Luffy之课程详情页 提前写好课程详情的template,并放入到Vue中 注册路由 import CourseDetail from "../components/CourseDetai ...

  7. Android app图标总是显示默认的机器人图标,且在manifest文件的application中修改无效...

    问题描述:我使用的开发工具是eclipse,Android app默认的图标是一个机器人,如下图所示 现在我要将app的图标修改成另外一个图标: 探索过程: 首先想到修改Manifest文件中的app ...

  8. python -- 字典 集合

    1.字典          定义:字典是以 key :value 的形式来保存数据,用{} 来表示,存储的是 key : value        查找效率比较高(注:字典存储数据时,用的是hash值 ...

  9. Python scrapy爬取带验证码的列表数据

    首先所需要的环境:(我用的是Python2的,可以选择python3,具体遇到的问题自行解决,目前我这边几百万的数据量爬取) 环境: Python 2.7.10 Scrapy Scrapy 1.5.0 ...

  10. day20_python_1124

    01 昨日内容回顾 类的名称空间 对象的空间 class A: def __init__(): pass obj = A() 对象查询属性:对象本身 ----> 类 -----> 父类 类 ...