尽可能以交易方式发送邮件

时间:2010-10-25 10:02:13

标签: java transactions synchronization email

我有一个简单的程序,每隔一段时间轮询一次数据库表,并发送表指示正在等待的任何邮件(使用javax.mail)。发送邮件时,我删除了数据库条目。

我注意到两个潜在的问题

  • 有可能发送邮件然后崩溃,所以数据库条目仍然存在。下次邮件将再次发送。
  • 可能有很多邮件要发送,所以我加载所有待处理的条目,全部发送,然后删除所有数据库条目。如果发送了一些/所有邮件,某些内容会失败,并且该作业会再次运行,那么它会使许多人陷入两次垃圾邮件。

这不是垃圾邮件应用程序,所以我想尝试避免两次发送任何内容,并确保我永远不会“丢失”邮件。

这是一个普遍的问题我确定哪里有两个不能参与交易的物理资源(DB +别的东西)所以我想知道人们用什么方法来减少/消除这个案例的问题/或一般情况。

2 个答案:

答案 0 :(得分:1)

我对您的问题有一个简单的解决方案。在名为'Pulled'

的数据库中添加一个字段

检查Pulled = 0然后提取数据,更新'Pulled' = 1并发送电子邮件。发送电子邮件后删除条目。

根据您用来发送电子邮件的方法,您可以抓住电子邮件以确保发送电子邮件。

如果初次检查'Pulled' = 1,那么您知道存在错误,您必须决定是否冒着重新发送电子邮件或删除电子邮件的风险并冒着丢失电子邮件的风险。

你肯定知道两件事。

(1)如果'Pulled' = 0,则尚未发送电子邮件。

(2)如果'Pulled' = 1,则在发送或删除过程中发生错误。

答案 1 :(得分:0)

我肯定会单独从数据库中读取每封邮件,以避免您描述的第二个问题。

锁定数据库行(例如select for update),以防多个进程同时运行(即使您不打算这样做,也可能由于部署不正确而偶然发生,有些失败) - 当原始服务仍在运行时激活,...)

在您对事务执行commit之前发送邮件,或者向某个异步系统发送消息,例如通过JMS。但更简单的解决方案就是尽可能在commit之前发送电子邮件。如果邮件出现问题,您可以回滚。如果没有出错,commit不太可能出现问题,所以你可能没问题。

否则,如果这不适合您正在使用的软件设计(例如,从某种业务逻辑方法发送电子邮件,以及由更高级别的流程管理的事务),那么您可以创建电子邮件对象并将其放入一个列表。在提交之前,您可以查看此列表并发送电子邮件。通过这种方式,电子邮件变得更具交易性,即只有在您提交时才会发送电子邮件。