2017年計(jì)算機(jī)等考三級(jí)數(shù)據(jù)庫輔導(dǎo):多線程下不重復(fù)讀取SQLServer的數(shù)據(jù)

字號(hào):

  在進(jìn)行一些如發(fā)送短信、郵件的業(yè)務(wù)時(shí),我們經(jīng)常會(huì)使用一個(gè)表來存儲(chǔ)待發(fā)送的數(shù)據(jù),由后臺(tái)多個(gè)線程不斷的從表中讀取待發(fā)送的數(shù)據(jù)進(jìn)行發(fā)送,發(fā)送完成后再將數(shù)據(jù)轉(zhuǎn)移到歷史表中,這樣保證待發(fā)送表的數(shù)據(jù)一般情況下不會(huì)太多。如待發(fā)送表結(jié)構(gòu)為:
    Create Table SMS(ID int not null identity(1,1),Content varchar(1024),Status int not null,CreateTime datetime);
    Status 取值:0未讀取 1已讀取
    這樣設(shè)計(jì)的好處是,不會(huì)因?yàn)楹蠖擞袝r(shí)發(fā)送過慢導(dǎo)致前端接收發(fā)送消息的請(qǐng)求出現(xiàn)問題,如發(fā)送短信的業(yè)務(wù),有時(shí)由于運(yùn)營商的網(wǎng)關(guān)原因發(fā)送太慢,這樣前端可以先將用戶的發(fā)送請(qǐng)求全部放在待發(fā)送表中,由后端進(jìn)行慢慢發(fā)送。
    在后端發(fā)送進(jìn)程一般使用
    Select top 100 * From SMS Where Status=0;這樣的SQL取出未被讀取的數(shù)據(jù)。
    為了提高后端發(fā)送能力,需要部署多個(gè)進(jìn)程同時(shí)從待發(fā)送表中取出數(shù)據(jù)進(jìn)行發(fā)送,這樣有時(shí)就會(huì)造成同一個(gè)記錄被多個(gè)進(jìn)程同時(shí)取出來,并發(fā)送的情況。
    今天查了一下SQL Server 的MSDN,發(fā)現(xiàn)可以通過先更新同時(shí)通過deleted表(就像是在觸發(fā)器中使用一樣)取出的方式,來保證每條記錄只會(huì)被讀取一次。
    declare @Rowid table(rowid int);
    BEGIN
    set rowcount 100; --一次讀取的行數(shù)
    --先將要讀取的記錄狀態(tài)更新
    update Sms set [status]= 1  output deleted.ID into @Rowid Where [status] = 0;   --讀取剛更新狀態(tài)的記錄
    select  * from Sms where ID in (select Rowid from @Rowid);
    END