在javaee中执行方法之前,正在寻找一种强制hibernate提交所有内存中事务的方法。当用户执行某些操作时,我们会向其发送一封电子邮件,前几天我们遇到了一个问题,用户收到了一封电子邮件,但包含数据的服务器已被填满,并且hibernate无法提交事务。一个罕见的病例,当然,但我们希望在将来避免它。因此,工作流应按以下方式运行:
用户执行操作
hibernate向数据库提交操作
系统向用户发送电子邮件
如果第2步失败,应用程序调用应该失败,这样它就不会发送电子邮件并通知用户。如果有帮助的话,我们正在wildfly服务器上运行hibernate和jpa。我有一个使用实体管理器的flush()方法的解决方案,但我知道这些事务仍然可以回滚。我也知道我们可以 @Transactional
,但我希望在发送电子邮件的方法中实现逻辑,而不是在外部方法中实现逻辑,以便在调用该方法时它可以执行相同的操作,并且我们不必担心以后会忘记它。
1条答案
按热度按时间wi3ka0sx1#
确保事务最终提交的唯一方法是,实际上提交事务。这意味着您应该首先提交事务,并且只在事务完成后执行不可逆的操作(如发送通知)。
当然,这为您的电子邮件通知功能引入了最多一次的传递语义,因为系统可能仍然会在#2和#3之间出现故障。您至少需要切换到一次,以确保每个完成的事务最终都会发送电子邮件通知。
最简单的解决方案是引入一个表作为传出电子邮件的队列(或者,一个布尔值)
email_sent
状态列),再加上一个后台作业,该作业将拾取所有挂起的通知、发送电子邮件并将通知标记为完成。总而言之,情况应该是这样的
用户执行操作
您的应用程序执行必要的业务逻辑并保存事务中的更改
在同一事务中,向
outgoing_notifications
table有两件事会发生:
(快乐路径)事务被提交,作业被完成,电子邮件被安排发送
(可选路径)事务提交失败(因此,在
outgoing_notifications
因此不会发送电子邮件一个背景,周期性的任务,然后:
阅读
outgoing_notifications
table发送发送的电子邮件
删除与成功发送的电子邮件通知对应的行
而不是用一张table
outgoing_notifications
当然,您可以使用另一种解决方案,例如持久消息/任务队列(前提是它在接收新任务时可以参与原始事务)。然而,我相信上面的解决方案是最可靠和最简单的。