首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Grails 2.4.4:如何在复杂服务方法中可靠回滚

Grails 2.4.4:如何在复杂服务方法中可靠回滚
EN

Stack Overflow用户
提问于 2015-01-30 18:14:46
回答 2查看 3.1K关注 0票数 11

考虑以下服务(默认情况下是事务性的)。玩家必须总是有一个帐户。没有至少一个相应帐户的播放器是错误状态。

代码语言:javascript
复制
class playerService {
   def createPlayer() {
      Player p new Player(name: "Stephen King")
      if (!p.save()) {
         return [code: -1, errors:p.errors]
      }
      Account a = new Account(type: "cash")
      if (!a.save()) {
         // rollback p !
         return [code: -2, errors:a.errors]
      }
      // commit only now!
      return [code: 0, player:p] 
   }
 }

我见过经验丰富的grails开发人员的这种模式,当我告诉他们,如果由于任何原因创建该播放器的帐户失败,它不会回滚播放机,并且会使DB处于无效状态,他们看着我就好像我很生气,因为grails处理回退播放器,因为服务是事务性的,对吗?

因此,作为一个SQL用户,我想找一种在grails中调用回滚的方法。根本就没有。根据不同的帖子,在服务中强制回滚grails的方法只有2种:

  1. 抛出未经检查的异常。你知道这是对的吗?
  2. 不要使用服务方法或事务注释,请使用以下构造:

代码语言:javascript
复制
DomainObject.withTransaction {status ->
     //stuff
     if (someError) {
        status.setRollbackOnly()
     }
}

1.引发未经检查的异常

1.1因此,我们必须将运行时异常抛出回滚。这对我来说没问题(我喜欢异常),但是我们的grails开发人员将异常视为Java的回滚,这是不酷的。这也意味着我们必须改变应用程序目前使用其服务层的整个方式。

1.2如果抛出异常,则会丢失p.errors --丢失验证细节。

1.3我们的新grails不知道未经检查的异常和被检查的异常之间的区别,也不知道如何区分它们。这真的很危险

1.4。使用.save(failOnError: true)我非常喜欢使用这个,但它并不适合在任何地方使用。有时,您需要在进一步研究之前检查原因,而不是抛出异常。它可以生成的异常总是检查的,总是未检查的,还是两者之一?也就是说,无论是什么原因,failOnError都会回滚吗?我问过的任何人都不知道这个问题的答案,这是令人不安的,他们是用盲目的信仰来避免腐败/不一致的DBs。

1.5如果控制器调用服务A (后者调用服务B ),那么服务C会发生什么情况。服务A必须捕获任何异常并将格式良好的返回值返回给控制器。如果Service抛出一个异常,被服务A捕获,那么服务B事务会被回滚吗?这对于知道如何构建一个工作的应用程序是至关重要的。

更新1:在做了一些测试之后,似乎任何运行时异常,即使在一些无关的子调用中抛出和捕获,都会导致父进程中的所有内容回滚。但是,在父会话中很难知道这个回滚已经发生了--您需要确保如果您捕获任何异常,要么重新抛出,要么将一些通知传递给调用方,以表明它已经失败,从而使其他所有东西都回滚。

2. withTransaction

2.1这似乎是一个集市结构。我如何调用它,以及传递给“状态”参数的是什么?"setRollbackOnly“到底是什么。为什么它不只是叫做“回滚”。“唯一”部分是什么?当您的方法可能想要更新几个不同的域对象时,它会绑定到域对象。

2.2你应该把这段代码放在哪里?和DomainObject类一起吗?在源文件夹中(即不在服务或控制器中?)?直接在控制器里?(我们不想在控制器中重复业务逻辑)

3.理想情况.

3.1一般情况是,如果服务方法中的任何内容因任何原因无法保存,或者出于任何原因(检查或未检查)抛出异常,我们希望在服务方法中所做的每一件事都回滚。

3.2理想情况下,我希望服务方法“总是回滚,除非我显式调用提交”,这是最安全的策略,但我认为这是不可能的。

问题是我怎样才能达到理想的情况?

无论失败的原因是什么,调用save(failOnError:true)总是会回滚所有东西吗?这并不完美,因为调用方不容易知道是哪个域对象保存导致了问题。

还是人们定义了大量的异常类,哪个子类是runtimeException,然后在控制器中显式捕获每个类以创建适当的响应?这是一种旧的Java方式,我们的groovy开发了这种方法,因为我们需要编写大量的锅炉板代码。

人们用什么方法来实现这一点?

EN

Stack Overflow用户

发布于 2017-11-23 17:16:56

如果您有这样的服务,比如:在Grails 2应用程序中,推荐的方法是使用transactionStatus.setRollbackOnly()

代码语言:javascript
复制
import grails.transaction.Transactional

Class RoleService {

    @Transactional
    Role save(String authority) {
        Role roleInstance = new Role(authority: authority) 
        if ( !roleInstance.save() ) {
           // log errors here
           transactionStatus.setRollbackOnly()
        }
        roleInstance
    }

}

请参阅:https://github.com/grails/grails-core/issues/9212

票数 0
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28242153

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档