1

我有以下代码代码,其中我尝试保存用户,然后发送“单击此链接以确认您的帐户”电子邮件

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()

那么事务确实会回滚,所以我假设这是因为发送邮件时发生的异常在不同的线程中,并且在抛出此异常时事务已经提交,这是正确的吗?

有没有一种方法可以事务性地保存用户并发送电子邮件,即保证只有在成功发送电子邮件时才保存用户?

更新

如果未发送电子邮件,我应该解释为什么我不想保存用户。原因是该电子邮件包含“确认您的帐户”链接,因此如果未发送此电子邮件,他们将无法完成注册过程并且将无法再次尝试注册(如果用户已保存) 因为用户名有唯一的约束。

4

1 回答 1

0

回答这个问题: -有没有一种方法可以事务性地保存用户并发送电子邮件,即保证只有在成功发送电子邮件时才保存用户?

正如@Sergio Michels 所提到的,是的,有一种更有效的方式来使用服务类,如下所示:-

您应该必须将throw异常排除在事务之外才能自动回滚事务。我通常在service默认事务的层中执行此操作。我必须将异常从服务层抛出到控制器或任何端点。

例如:

def someServiceMethod{
        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)

        //Rethrown out to controller automatically, 
        //which results in roll back of transaction
}

def sendRegistrationEmail(username, randomPassword){
    throw new Error() //will rollback the transaction
}

在您的情况下,请确保您没有在内部捕获异常sendRegistrationEmail。如果是,那么您必须重新向呼叫者抛出。

PS:-我有相同的实现,但是如果发送邮件有任何问题,我会吃异常,而不是回滚,因为问题出在邮件服务而不是我的用户保存服务中,用户为什么要受苦。:-)

更新:-
如果您在控制器中有代码并使用withTransaction. 在您的方法中,如果您在其他任何地方使用 Hibernate 会话来保留除了您在问题中的逻辑之外的一些其他数据,那么您需要清除 catch 块中的会话,否则用户数据将flushed在后续操作中进入数据库.

catch(ex){
  object.discard()
  status.rollbackOnly()
}

第二次尝试
您可以尝试包装您旋转的新线程withTransaction,看看是否所有事务都回滚了。

推论:-
不将事务处理为样板代码,decleratively在服务中处理事务比在其他任何地方以编程方式处理事务更方便。

于 2013-06-05T19:04:43.183 回答