2012-11-09 52 views
1

我有以下結構:行爲循環的一個事務中

PROCEDURE A 

BEGIN TRANSACTION 
    WHILE <loops 20 times> 
     BEGIN 

     --10 minute script  
     --INSERT a single record into table X 

     END 
COMMIT TRANSACTION 


PROCEDURE B - This is run via the agent every 10 minutes it scans table X for any new entries and if it finds any it sends an e-mail 

如果一切運行正常20條新的記錄將被添加到表X - 將在所有20圈這些記錄只被添加到X已經成功了嗎?如果循環到達第5次迭代,那麼前4個記錄會被提交出錯?

+0

這是什麼,你正試圖完成? –

+0

@ Clockwork-Muse表X實際上是一個控制表,用於需要通過'db_sendmail'發送的電子郵件...'PROCEDURE B'正在掃描尋找需要發送的新郵件。我只想要'PROC A'的郵件去或不去它們。我想避免的是一些郵件。 – whytheq

回答

4

那麼,舉行一個交易開放10分鐘是邪惡的。持有10分​​鍾20次交易是好的,20倍的惡。長期存在的交易非常非常具有破壞性,並且會在鎖定和阻塞,日誌使用和增長以及恢復問題方面造成嚴重問題。永遠不要設計任何交易時間超過的交易。時間讓你重新審視你正在努力解決的根本問題,並提出一個完全不同的解決方案。

至於核心問題:事務可以在這樣的迭代中使用保存點,這樣即使迭代5遇到問題並且需要回滾,迭代1-4也會被保存(提交)。訣竅是回滾到一個保存點,而不是完全。遵循與Exception Handling and Nested Transactions中相同的模式。請注意,不是錯誤是可恢復的,有些錯誤會強制完成回滾(例如,死鎖是一個典型示例)。

+0

....我不像你想的那麼邪惡;我採取了實際的時間,並將它們誇大爲更加極端的情況,希望能夠得到更好的答案,然後更安全,更防守的代碼。 – whytheq

+0

好吧,也許一個徹底的變化就像:我可以簡單地在每個循環迭代結束時添加每行到中間臨時表。然後,一旦代碼完成循環,它可以將臨時表中的所有數據「插入」 - 您怎麼看?剛回到_「秒」_ - 你是否暗示一分鐘以內的交易沒有問題? – whytheq

+2

對於你所描述的(發送所有郵件或不發送)登臺表似乎是合適的。通過這種方式,您可以準備單個事務中的所有工作,然後在一次事務中將暫存表中累積的所有項目轉換爲sp_send_mail調用。 –

1

這裏的答案是不是100%的直截了當:

他們將被添加到內存中的數據頁,因爲他們被插入在每個循環的結束,如果另一個進程使用READ UnCOMITTED或無鎖跑那麼他們將能夠看到這些插入。這被稱爲Dirty Reads,REAd COMMITED的默認隔離級別可以防止這種情況發生,但這也意味着交易將被阻止在此級別下讀取,直到循環完成。

但是,SQL Server可以隨時選擇將髒頁面刷新到光盤。我的意思是,在交易結束之前,交易結束時或交易完成後。

可以肯定的是,在提交之前,寫入將在事務結束時刷新到事務日誌。這就是數據庫關閉時SQL Server高速數據不會丟失的原因。這稱爲WAL或預寫日誌。

+0

我可以修改'PROC B'中的代碼,以便強制**不**讀取'UNCOMMITTED'數據? – whytheq

+0

除非你專門設置了讀未提交或使用無鎖提示,否則默認是讀提交,這將防止這種情況發生?它只會坐在那裏,等待進程完成,除非有一個鎖定超時設置,當它會崩潰 –

相關問題