Java 交易和发送电子邮件

Java 交易和发送电子邮件,java,spring,email,transactions,Java,Spring,Email,Transactions,考虑用户在web应用程序上创建新帐户以及应用程序向用户地址发送确认电子邮件的常见用例。据我所见,这通常通过以下三种方式之一实现: web控制器调用一个服务方法,该方法在单个事务中创建用户帐户并发送电子邮件 web控制器调用一个服务方法(tx propagation=never),该方法调用自身的第一个方法来在事务中创建用户帐户,然后调用自身的第二个方法来发送电子邮件 web控制器调用第一个服务方法(在事务中创建用户帐户),然后调用第二个服务方法(发送电子邮件) 第一种方法简单明了,但存在在发送电

考虑用户在web应用程序上创建新帐户以及应用程序向用户地址发送确认电子邮件的常见用例。据我所见,这通常通过以下三种方式之一实现:

  • web控制器调用一个服务方法,该方法在单个事务中创建用户帐户并发送电子邮件
  • web控制器调用一个服务方法(tx propagation=never),该方法调用自身的第一个方法来在事务中创建用户帐户,然后调用自身的第二个方法来发送电子邮件
  • web控制器调用第一个服务方法(在事务中创建用户帐户),然后调用第二个服务方法(发送电子邮件)
  • 第一种方法简单明了,但存在在发送电子邮件后事务回滚的风险,从而使电子邮件无效。第二种方法更复杂,但它保证只有在用户创建实际成功时才发送电子邮件。第三种方法很简单,但给web层带来了不需要知道的业务逻辑

    难道没有一种更简单的方法,可能是AOP驱动的,可以保证只有在用户创建事务实际成功时才能发送电子邮件吗?我是否偏执地认为第一种方法可能会失败

    我们正在使用JavaEE+Spring堆栈,并愿意集成其他API(AOP?Spring集成?)来实现这一点


    干杯

    要发送电子邮件,建议使用队列并安排每5或15分钟发送一次电子邮件。 队列将存储在数据库中,因此在事务中。然后安排一个过程,定期从该队列发送电子邮件


    这是我发现的确保只有在事务完成并提交时才发送电子邮件的唯一方法,因为根据定义,电子邮件不与任何类型的数据库事务相关联。

    我想为电子邮件添加一个轻量级JMS层,如ActiveMQ,它非常容易设置并与Spring集成(甚至嵌入)。那你有

    1) 用户创建事务&在1个事务中发送JMS消息。如果其中一个失败,您仍然处于良好状态(提交或回滚,并且向用户显示错误)


    2) 如果JMS使用者无法发送电子邮件,您可以设置JMS队列重试几次,这样您就有了更好的解决方案来管理电子邮件系统的暂时性问题

    我目前正在使用的解决此问题的另一个选项:


    使用数据库表进行排队,并使用Quartz或类似工具运行调度程序,这些都是合理且易于实现的

    在这些特性开发中使用RabbitMQ也是一个好主意。RabbitMQ非常易于配置,在大多数情况下可用于发布/订阅系统之间的互通,即使您可能需要实现应用程序级ack和小型应用程序,从RabbitMQ订阅消息并通过SMTP发送电子邮件


    这听起来可能有些过分,但您可以将此#2解决方案用于将来需要发送电子邮件的每个系统。对此,您仍然可以使用基于数据库队列的模型,但将使用昂贵的数据库cpu/资源来发送emmail。

    有趣的是,我不知道API的这一部分。不幸的是,我们没有在我们的环境中使用JTA(仅资源本地事务),因此这种方法不是可行的选择。我也在使用本地tx和Spring托管tx,它允许我注册同步对象:
    public void sendMailAfterCommit(final MailManager邮件){TransactionSynchronizationManager.registerSynchronization(新TransactionSynchronizationAdapter(){@Override public void afterCommit(){mailService.sendMail(mail);}}}}
    这似乎是一件合乎逻辑的事情。它对性能也有好处:您的控制器不必等待电子邮件真正发送,但它可以立即返回给用户。这似乎也是一件合乎逻辑的事情。我不熟悉JMS,所以我想知道:如何才能注册发送JMS消息和更新数据库同一事务?我们是否需要设置XA事务来实现这一点,因为JMS持久存储不一定是应用程序数据库?