Grails服务事务 [英] Grails Service Transactions

查看:124
本文介绍了Grails服务事务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让事务在Grails服务中工作,但我没有得到我期待的结果。有人告诉我,如果我做错了什么,如果我的假设是关闭的?



我的域类:

  class Account {

static constraints = {
balance(min:0.00)
}

字符串companyName
BigDecimal余额= 0.00
布尔值active = true

字符串toString(){
return$ {companyName}:$ {余额}

}

我的服务:

  class AccountService {

static transactional = true

def传输(帐户来源,帐户目的地,金额)引发RuntimeException {

if(source.active&& destination.active){
source.balance - = amount

if(!source.save(flush:true)){
throw new RuntimeException(Could not save source account。)
} else {
destination.balance + = amount

if(! destination.save(flush:true)){
抛出新的RuntimeException(无法保存目标帐户。)
}
}
} else {
throw new RuntimeException(两个帐户必须处于活动状态。)
}
}

def someMethod(帐户帐户)引发RuntimeException {

account.balance = -10.00
$ b printlnvalidated:$ {account.validate()}

if(!account.validate()){
throw new RuntimeException(回滚!)
}
}
}

我的单元测试: import grails.test。*

  class AccountServiceTests extends GrailsUnitTestCase {

帐户服务

保护无效setUp(){
super.setUp()
mockDomain(帐户)
AccountService = new AccountService()


保护无效tearDown(){
super.tearDown()
}

void testTransact ional(){
def account = new Account(companyName:ACME Toy Company,余额:2000.00,active:true)
$ b $ def例外=空

尝试{
AccountService.someMethod(account)
} catch(RuntimeException e){
exception = e
}

assert exception instanceof RuntimeException

println异常抛出:$ {exception.getMessage()}

assertEquals 2000.00,account.balance
}
}

结果:

  Testsuite:AccountServiceTests 
测试运行:1,失败:1,错误:0,流逝时间:1.068秒
-------------标准输出---------------
- 从testTransactional输出 -
验证:false
抛出异常:回滚!
------------- ---------------- ---------------
-------------标准错误-----------------
- 从testTransactional输出 -
- ------------ ---------------- ---------------

Testcase:testTransactional花了1.066秒
失败
预期值:< 2000.00>但是:< -10.00>
junit.framework.AssertionFailedError:expected:< 2000.00>但是:< -10.00>
at AccountServiceTests.testTransactional(AccountServiceTests.groovy:89)
at _GrailsTest_groovy $ _run_closure4.doCall(_GrailsTest_groovy:203)
at _GrailsTest_groovy $ _run_closure4.call(_GrailsTest_groovy)
at _GrailsTest_groovy $ $ _ $ _ at _GrailsTest_groovy $ _run_closure1_closure19.doCall(_GrailsTest_groovy:113)
at _GrailsTest_groovy $ _run_closure1.doCall(_GrailsTest_groovy:96)
at TestApp $ _run_closure1.doCall(TestApp(_GrailsTest_groovy: .gov。:66)
at gant.Gant $ _dispatch_closure4.doCall(Gant.groovy:324)
at gant.Gant $ _dispatch_closure6.doCall(Gant.groovy:334)
at gant。 Gant $ _dispatch_closure6.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:344)
at gant.Gant.this $ 2 $ withBuildListeners(Gant.groovy)
at gant.Gant $ this $ 2 $ withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:334)
at gant.Gant.this $ 2 $ dispatch(Gant (Gant.groovy)
at gant.invokeMethod(Gant.groovy)
at gant.Gant.processTargets(Gant.groovy:495)
at gant.Gant.processTargets(Gant.groovy: 480)

我的期望:



当帐户被赋予一个负余额时,它不应该被验证(它不会),应该抛出一个RuntimeException(它是),并且该帐户应该回滚到它以前的状态(余额:2000),这是它分崩离析的地方。



我在这里错过了什么?

解决方案

单元测试只是Groovy或Java类,所以没有Spring应用程序上下文,因此没有事务支持。你不得不嘲笑单元测试,但这不会测试事务性,只是模拟的质量。将此转换为集成测试,并且不要在服务上调用new,请使用依赖注入:

 类AccountServiceTests扩展GroovyTestCase {

帐户服务

无效testTransactional(){
def帐户=新帐户(公司名称:ACME玩具公司,余额:2000.00,
活动: true)
account.save()
assertFalse account.hasErrors()

String message = shouldFail(RuntimeException){
AccountService.someMethod(account)

$ b println异常抛出:$ message

assertEquals 2000.00,account.balance
}
}

$ b

请注意,实际的异常可能是一个包装异常,因为您的抛出异常是其原因。


I'm trying to get transactions working within a Grails service, but I'm not getting the results I'm expecting. Can someone tell me if I'm doing something wrong, if my assumptions are off?

My domain class:

class Account {

  static constraints = {
    balance(min: 0.00)
  }

  String companyName
  BigDecimal balance = 0.00
  Boolean active = true

  String toString() {
    return "${companyName} : ${balance}"
  }
}

My service:

class AccountService {

  static transactional = true

  def transfer(Account source, Account destination, amount) throws RuntimeException {

    if (source.active && destination.active) {
      source.balance -= amount

      if (!source.save(flush: true)) {
        throw new RuntimeException("Could not save source account.")
      } else {
        destination.balance += amount

        if (!destination.save(flush: true)) {
          throw new RuntimeException("Could not save destination account.")
        }
      }
    } else {
      throw new RuntimeException("Both accounts must be active.")
    }
  }

  def someMethod(Account account) throws RuntimeException {

    account.balance = -10.00

    println "validated: ${account.validate()}"

    if(!account.validate()) {
      throw new RuntimeException("Rollback!")
    }
  }
}

My unit test: import grails.test.*

class AccountServiceTests extends GrailsUnitTestCase {

  def AccountService

  protected void setUp() {
    super.setUp()
    mockDomain(Account)
    AccountService = new AccountService()
  }

  protected void tearDown() {
    super.tearDown()
  }

  void testTransactional() {
    def account = new Account(companyName: "ACME Toy Company", balance: 2000.00, active: true)

    def exception = null

    try {
      AccountService.someMethod(account)
    } catch (RuntimeException e) {
      exception = e
    }

    assert exception instanceof RuntimeException

    println "exception thrown: ${exception.getMessage()}"

    assertEquals 2000.00, account.balance
  }
}

The result:

Testsuite: AccountServiceTests
Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 1.068 sec
------------- Standard Output ---------------
--Output from testTransactional--
validated: false
exception thrown: Rollback!
------------- ---------------- ---------------
------------- Standard Error -----------------
--Output from testTransactional--
------------- ---------------- ---------------

Testcase: testTransactional took 1.066 sec
    FAILED
expected:<2000.00> but was:<-10.00>
junit.framework.AssertionFailedError: expected:<2000.00> but was:<-10.00>
    at AccountServiceTests.testTransactional(AccountServiceTests.groovy:89)
    at _GrailsTest_groovy$_run_closure4.doCall(_GrailsTest_groovy:203)
    at _GrailsTest_groovy$_run_closure4.call(_GrailsTest_groovy)
    at _GrailsTest_groovy$_run_closure2.doCall(_GrailsTest_groovy:147)
    at _GrailsTest_groovy$_run_closure1_closure19.doCall(_GrailsTest_groovy:113)
    at _GrailsTest_groovy$_run_closure1.doCall(_GrailsTest_groovy:96)
    at TestApp$_run_closure1.doCall(TestApp.groovy:66)
    at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)
    at gant.Gant$_dispatch_closure6.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:344)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:334)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.processTargets(Gant.groovy:495)
    at gant.Gant.processTargets(Gant.groovy:480)

My expectation:

When the account is given a negative balance, it shouldn't validate (which it doesn't), a RuntimeException should be thrown (which it is), and the account should rollback to it's previous state (balance: 2000), which is where it falls apart.

What am I missing here?

解决方案

Unit tests are just Groovy or Java classes, so there's no Spring application context and hence no transaction support. You'd have to mock that for a unit test, but that wouldn't be testing transactionality, just the quality of the mocks. Convert this to an integration test and don't call new on the service, use dependency injection:

class AccountServiceTests extends GroovyTestCase {

  def AccountService

  void testTransactional() {
    def account = new Account(companyName: "ACME Toy Company", balance: 2000.00,
                              active: true)
    account.save()
    assertFalse account.hasErrors()

    String message = shouldFail(RuntimeException) {
      AccountService.someMethod(account)
    }

    println "exception thrown: $message"

    assertEquals 2000.00, account.balance
  }
}

Note that the actual exception may be a wrapper exception with your thrown exception as its cause.

这篇关于Grails服务事务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆