数据库中有表[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. vmware中虚拟化的问题

    因为用的是Window系统,又不想换系统,所以在学习Linux时,使用的VMware来安装的Centos,想在VMware中安装KVM虚拟机,然后报错,说我没有打开虚拟化,我使用 的是Surface ...

  2. Java Deque 队列 栈

    垃圾JDK啊 Deque这个接口,既承担着FIFO的任务,即队列,也承担着LIFO的任务,即栈 目前jdk里面实现了这个接口的类有两个,一个是ArrayDeque,另一个是LinkedList 但是由 ...

  3. JxBrowser之一:Java嵌入Chrome浏览器

    1.JxBrowser是一个让Java可以轻松集成Chrome浏览器的跨平台库:一般用于网络爬虫或者网页自动化测试等. 官方网址:https://jxbrowser.support.teamdev.c ...

  4. [Database] Oracle 中的where 可以后接group by

    SELECT e.DEPTNO,COUNT(e.EMPNO) FROM emp e WHERE e.DEPTNO=10 GROUP BY e.DEPTNO

  5. Strut2页面传参跳转 --Struts2

    1.本案例借助struts2框架,完成页面传参.跳转功能 2.代码实现 index.jsp: <form action="helloStruts2.action" metho ...

  6. vue的组件之间传值方法

    父组件 <template> <div> 这是父组件 <children v-bind:parentToChild="toChild" v-on:sh ...

  7. php同curl post 发送json并返回json数据实例

    <?php $arr = array( 'subject'=>'课程', 'loginName'=>'Durriya', 'password'=>'123' ); //json ...

  8. 下载配置nodeJs,cnpm,webpack,vue-cli等,刚装的系统,所有东西重新配置

    最近重新装了系统,所有的环境都要重新配置了,做个笔记. 安装nodeJs: 可以参照教程:https://www.runoob.com/nodejs/nodejs-install-setup.html ...

  9. Session&Cookie(Introduction、Application)

    一Session 1概念: (1)session是会话,是同一连接者所有页面公有的内置对象   (2)session是一段时间,从session创建开始,到session销毁结束,默认时间为30分钟( ...

  10. eclipse快捷键大全(转载自CSDN)

    Ctrl+1 快速修复(最经典的快捷键,就不用多说了) Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加) Ctrl+Alt+↑ 复制当前行到上一行(复制增加) Alt+ ...