2010-10-25 19 views
1

我有一個簡單的程序,每隔一段時間輪詢一次數據庫表,併發送表中指示爲掛起的任何郵件(使用javax.mail)。郵件發送時,我刪除數據庫條目。儘可能以事務方式發送郵件

我注意到兩個潛在的問題

  • 有發送郵件的可能性,然後崩潰的東西所以DB項是仍然存在。下一次郵件將再次發送。
  • 可能會有大量郵件發送,因此我加載所有待處理的條目,將它們全部發送,然後刪除所有數據庫條目。如果某些/所有郵件被髮送,某些內容會失敗,並且該作業會再次運行,然後會讓很多人感染兩次。

這不是一個垃圾郵件應用程序,所以我想嘗試避免發送任何兩次,確保我永遠不會「丟失」一條消息。

這是一個普遍問題我確定哪裏有兩個物理資源不能參與事務(DB +別的東西),所以我想知道人們用什麼方法來減少/消除這種情況下的問題和/或一般情況。

回答

0

我肯定會從數據庫中逐個讀取每封郵件,以避免您描述的第二個問題。

在數據庫行上放置一個鎖(例如select for update)以防萬一多個進程同時運行(即使您不打算髮生這種情況,由於部署不正確,可能會意外發生,但某些故障切換激活當原始服務仍在運行時,..)

可以在您對事務執行commit之前發送郵件,或者發送消息給某個異步系統,例如通過JMS。但更簡單的解決方案只是在commit之前發送電子郵件,如果可能的話。如果郵件出現問題,可以回滾。如果沒有出現問題,那麼commit不太可能會出現問題,所以你可能沒問題。否則,如果這不符合您正在使用的軟件設計(例如,電子郵件是從一些業務邏輯方法發送的,並且事務由更高級別的進程管理),那麼您可以創建Email對象並將它們在一個列表中。就在提交之前,您可以查看此列表併發送電子郵件。通過這種方式,電子郵件變得更具事務性,即只有在您提交時才發送。

+0

這對我來說似乎很糟糕。您可以發送所有電子郵件,然後由於某些與電子郵件無關的原因而導致事務回滾,並且您已被搞砸。 – 2010-10-25 13:31:01

+0

@Nathan Hughes - 當然,存在這種風險,但如果您在提交之前發送它們,則可以通過最大限度地減少崩潰導致該情況的時間窗口來最大限度地降低風險。由於電子郵件不是事務性的(一旦它們被髮送,它們被髮送),沒有其他方式。 – 2010-10-25 13:47:27

1

我對你的問題有一個簡單的解決方案。在數據庫中添加一個字段,名爲'Pulled'

檢查Pulled = 0然後拉數據,更新'Pulled' = 1併發送電子郵件。郵件發送後刪除條目。

根據您用來發送電子郵件的方法,您可能會捕獲到適當的位置以確保發送電子郵件。

如果在初始檢查時出現'Pulled' = 1,那麼您知道存在錯誤,您必須決定是否冒重發電子郵件或刪除電子郵件的風險以及冒着丟失電子郵件的風險。

你肯定知道兩件事。

(1)如果'Pulled' = 0那麼電子郵件尚未發送。

(2)如果'Pulled' = 1則發送或刪除過程中發生錯誤。

相關問題