考虑以下服务(默认情况下是事务性的)。玩家必须总是有一个帐户。没有至少一个相应帐户的播放器是错误状态。
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种:
。
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开发了这种方法,因为我们需要编写大量的锅炉板代码。
人们用什么方法来实现这一点?
发布于 2017-11-23 17:16:56
如果您有这样的服务,比如:在Grails 2应用程序中,推荐的方法是使用transactionStatus.setRollbackOnly()。
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://stackoverflow.com/questions/28242153
复制相似问题