SQL Server 幻讀 的真實案例

來源:互聯網
上載者:User

標籤:單線程   可靠   指定   font   group   from   item   isolation   insert   

資料庫中有表[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 [‘[email protected]+‘_SubjectiveScoreInfoFlag](ID)                    SELECT TOP 100 SS.ID                    FROM [‘[email protected]+‘_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 [‘[email protected]+‘_SubjectiveScoreInfoFlag] WITH(UPDLOCK)                        WHERE ID = SS.ID                      )                                    COMMIT TRAN

UPLOCK是排它鎖,這樣就沒有死結了。

 

SQL Server 幻讀 的真實案例

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.