【发布时间】:2013-06-05 18:47:10
【问题描述】:
我有以下代码代码,其中我尝试保存用户,然后发送“单击此链接以确认您的帐户”电子邮件
User.withTransaction { TransactionStatus status ->
try {
Role userRole = Role.createCriteria().get {
eq 'authority', 'USER_ROLE'
}
user = user.save(failOnError: true)
UserRole.create user, userRole
// sends an email using the Grails mail plugin
sendRegistrationEmail(username, randomPassword)
redirect action: 'listUsers'
} catch (ex) {
status.rollbackOnly
}
}
我在事务中发送了电子邮件,因为如果在发送电子邮件期间引发异常,我希望回滚事务。但是我对此进行了测试(通过故意提供无效的邮件服务器凭据)并且在引发异常时事务不会回滚。
如果我替换:
sendRegistrationEmail(username, randomPassword)
与:
throw new Exception()
那么事务确实会回滚,所以我假设这是因为发送邮件时发生的异常是在不同的线程中,并且在引发此异常时事务已经提交,这是正确的吗?
有没有一种方法可以事务性地保存用户并发送电子邮件,即保证只有在成功发送电子邮件时才能保存用户?
更新
我应该解释为什么我不想在未发送电子邮件的情况下保存用户。原因是该电子邮件包含“确认您的帐户”链接,因此如果未发送此电子邮件,他们将无法完成注册过程,也无法再次尝试注册(如果用户已保存) 因为用户名有唯一的约束。
【问题讨论】:
-
你是如何发送邮件的?它是同步的还是异步的。
-
此代码在控制器中?而
sendRegistrationEmail正在服务中还是控制器方法?一个关键是控制器不是事务性的,但服务是。如果您将两者混合使用,您可能会遇到问题。 -
@SérgioMichels 代码包含在
User.withTransaction{}中,因此即使它在控制器中也是事务性的 -
@user2264997 邮件同步发送
-
@Don 是的,我说的是默认值,没有使用 withTransaction。即使您将控制器操作设置为事务性的,放置此逻辑的更好位置是在服务中。
标签: grails transactions grails-orm