数据库中有表[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是排它锁,这样就没有死锁了。

最新文章

  1. Linux的一些基本概述以及系统使用
  2. 条件随机场理论分析CRF(Conditional Random Field)
  3. splay总结
  4. 烂泥:KVM虚拟机windows系统增加硬盘
  5. php常用代码
  6. Django——model字段类型 2
  7. egret-android-support-gradle版
  8. Excel公式-求最低价网站名字
  9. 推荐几个Dynamic Crm的大神博客
  10. TCP模型及其重点协议总结
  11. sql 迈安
  12. Python 面向对象的补充
  13. opengl学习,一篇就够你基本了解
  14. 使用路由和远程访问服务为Hyper-V中虚拟机实现NAT上网
  15. 详细解读Volley(五)—— 通过源码来分析业务流程
  16. spring boot打jar包发布
  17. 知识点查缺补漏贴01-进程间通讯之mmap文件共享
  18. C# 浅谈 接口(Interface)的作用
  19. TypeScript 2 : 获取当前日期及前后范围日期【Array】
  20. 改变 Windows 用户文件夹默认位置

热门文章

  1. C# 视频多人脸识别的实现过程
  2. Angular4学习笔记(七)- ViewChild和ViewChildren
  3. python实现http get请求
  4. CSS选择器 nth-child 和 nth-of-type
  5. 获取页面定位元素left top
  6. MapRedcue的demo(协同过滤)
  7. commons-lang3工具类学习(三)
  8. navicat连接Oracle数据库
  9. Linux SSH登录很慢的解决方法
  10. 第五周作业--测试与版本发布(Alpha版本)