我花了十分钟时间弄清楚为什么我的单元测试对着测试数据库工作需要大约25秒来完成一个简单的查询。显然,原因是我忘记在ExecutionEngine#execute(String)
中打电话给Transaction
。
我不知道应该是可能的。 HMM。
我的代码看起来像这样:
...
@Before
public void before() {
db = new TestGraphDatabaseFactory().newImpermanentDatabase();
/* create all the test nodes and rels */
}
@After
public void after() {
db.shutdown();
}
@Test
public void testAllTheThings() {
/* build the cypher query */
Iterable<Map<String, Object>> result = engine.execute(cypher);
/* assert all the things */
}
...
这里令人困惑的部分是execute()
一次返回并执行以下语句。但是,测试在成功终止之前会停止约25秒。
将语句更改为以下内容按预期工作,没有任何延迟:
...
try (Transaction transaction = db.beginTx()) {
Iterable<Map<String, Object>> result = engine.execute(cypher);
}
...
这里到底发生了什么?为什么可以这样做?
答案 0 :(得分:3)
我怀疑你并没有因Iterator
返回的ExecutionResult
而感到筋疲力尽。如果这样做,测试将很快完成,而无需在事务中包装ExecutionEngine#execute()
。
这是我的想法,虽然我没有在调试器中重现它。
execute()
创建自己的事务,因此不必创建自己的事务。但是,必须关闭所有交易。在这种情况下,事务状态由记录here的ExecutionEngine#execute()
方法处理。如果您部分使用结果ExecutionResult
,则事务处于打开状态。
当您致电Iterator
时,它会尝试通过在强制关闭之前等待它们完成来容纳打开的交易。您在测试中看到的失速可能是超时发生。当然,在这种情况下,事务在等待期间不可能关闭,因为它由关闭数据库的同一线程持有。
由于事务与线程相关联,因此原则上GraphDatabaseService#shutdown()
可以检测到这种情况并在不等待的情况下关闭事务。但是,在生产代码中,同一个线程执行事务和控制数据库的情况可能很少见,因此额外的复杂性是不合理的。
处理此问题的最简单方法是始终确保耗尽GraphDatabaseService
返回的结果迭代器。