嵌套的内部事务已经提交的数据更改实际上应该在父事务中立即可见。
我真的不知道他们为什么是而不是在GroovyTestCase
的事务上下文中。 Others don't know, as well, and are using similar approaches to mine。
考虑下面的测试用例。测试用例本身是而不是事务性,但调用事务性方法。 - 这符合预期。
class TransactionalMethodTest extends GroovyTestCase {
static transactional = false // test case is not transactional
def customerService
void testTransactionsCommit() {
// start a new transaction,
// setting order 1 inactive
setOrderInactive()
assert ! Order.get(1).isActive
}
@Transactional(propagation = Propagation.REQUIRED)
private void setOrderInactive() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
customerService.cancelOrders([1])
// changes from the nested transaction are
// visible, instantly
assert ! Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
}
现在考虑以下“正常”事务性测试用例。嵌套事务中的数据更改是而不是在父事务中可见。
我只能说,事务测试用例不适用于嵌套事务,所以使用了高于的非事务测试用例。
如果我们不明白原因,我们至少可以知道我们的选择。
class TransactionalTestCaseTests extends GroovyTestCase {
static transactional = true // default; Propagation.REQUIRED
def customerService
void testTransactionsCommit() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
customerService.cancelOrders([1])
// the changes from the inner transaction
// are not yet visible
assert Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
@Override
protected void tearDown() throws Exception {
// the changes from the inner transaction
// are still not visible
assert Order.get(1).isActive
super.tearDown();
}
}
不相关的主要问题,但你的整体意图,这里是检查嵌套事务是否被回滚,正确的测试案例:
class NestedTransactionRolledBackTests extends GroovyTestCase {
static transactional = false // test case is not transactional
def customerService
void testTransactionsCommit() {
// start a new transaction,
// setting order 1 active
setOrderActive()
assert Order.get(1).isActive
}
@Transactional(propagation = Propagation.REQUIRED)
private void setOrderActive() {
// make sure that order 1 is active
Order order = Order.get(1)
order.isActive = true
order.save(flush:true)
assert Order.get(1).isActive
// the following method acts in isolation level
// Propagation.REQUIRES_NEW, which means,
// a new, nested, transaction is started.
// This transaction will fail, and be rolled back.
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
shouldFail(NullPointerException) {
customerService.cancelOrders([1, -999])
}
// changes from the nested transaction are
// visible, instantly.
// The changes have been rolled back
assert Order.get(1).isActive
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
}
}
最后,一些更一般的注解,它不是boolean transactional = true
(它似乎工作,虽然),但static transactional = true
。你的集成测试也应该extend
GroovyTestCase
,而不是它的子类GrailsUnitTestCase
,因为你不需要后者的嘲讽能力。 isActive
字段应该命名为active
,然后通过命名约定自动生成isActive()
getter。
谢谢,所以看起来这是一个集成测试框架的错误。即代码/逻辑是否正确,并在正在运行的应用程序中工作,但不在集成测试中?也许我应该JIRA它 – Sunny 2010-11-12 06:00:45
我不认为这是一个错误(这个问题太重要了/突出),而是一个设计缺陷。 - 如果您应该提交JIRA问题(使用Spring而不是Grails框架),请在此处留言。 – robbbert 2010-11-12 12:30:10
对最后一个示例(过时?)的更正:'Propagation.REQUIRES_NEW'开始一个新的_unrelated和independent_事务。相比之下,'Propagation.NESTED'下出现_nested_事务(对父对象和其自己的保存点可见)。 Spring Javadoc做了很好的解释差异:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html – 2015-02-05 14:45:00