[英]Detecting N+1 query issues during testing with JPA and Hibernate
我们正在使用https://github.com/vladmihalcea/db-util这是一个很棒的工具,但是我们面临着 Session 缓存的挑战,正如另一个问题中提到的,它不能被禁用。
因此,以下测试失败,因为findOne
从 session 缓存中获取 object:
@Test
public void validateQueries() {
// when (scenario definition)
TestObject testObject = new TestObject(1L);
repository.save(testObject);
SQLStatementCountValidator.reset();
repository.findOne(1L);
SQLStatementCountValidator.assertSelectCount(1);
}
每次调用SQLStatementCountValidator.reset()
时,都会调用entityManager.clear()
的解决方法。
现在,解决方法很好,但容易出错,因为现在我们必须注入 EntityManager 作为测试的依赖项,并记住在保存代表我们场景的所有对象后调用entityManager.clear()
。
问题
在这里可以查看日志语句(最后一条)
09:59.956 [main] [TRACE] o.h.e.i.AbstractSaveEventListener - Transient instance of: TestObject
09:59.957 [main] [TRACE] o.h.e.i.DefaultPersistEventListener - Saving transient instance
09:59.962 [main] [TRACE] o.h.e.i.AbstractSaveEventListener - Saving [TestObject#<null>]
Hibernate:
insert
into
test_object
(id, creation_time, "update_time", "name")
values
(null, ?, ?, ?)
10:00.005 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Flushing session
10:00.005 [main] [DEBUG] o.h.e.i.AbstractFlushingEventListener - Processing flush-time cascades
10:00.007 [main] [DEBUG] o.h.e.i.AbstractFlushingEventListener - Dirty checking collections
10:00.007 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Flushing entities and processing referenced collections
10:00.011 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Processing unreferenced collections
10:00.011 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Scheduling collection removes/(re)creates/updates
10:00.011 [main] [DEBUG] o.h.e.i.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
10:00.011 [main] [DEBUG] o.h.e.i.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
10:00.015 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Executing flush
10:00.015 [main] [TRACE] o.h.e.i.AbstractFlushingEventListener - Post flush
10:02.780 [main] [TRACE] o.h.e.i.DefaultLoadEventListener - Loading entity: [TestObject#1]
10:08.439 [main] [TRACE] o.h.e.i.DefaultLoadEventListener - Attempting to resolve: [TestObject#1]
10:08.439 [main] [TRACE] o.h.e.i.DefaultLoadEventListener - Resolved object in session cache: [TestObject#1]
com.vladmihalcea.sql.exception.SQLSelectCountMismatchException: Expected 1 statements but recorded 0 instead!
解决方法代码如下所示:
@Test
public void validateQueries() {
// when (scenario definition)
TestObject testObject = new TestObject(1L);
repository.save(testObject);
entityManager.clear();
SQLStatementCountValidator.reset();
repository.findOne(1L);
SQLStatementCountValidator.assertSelectCount(1);
}
每个测试都应该管理事务。 因此,您应该删除在 class 级别添加的@Transactional
注释。
所以,你注入一个TransactionTemplate
bean:
@Autowired
private TransactionTemplate transactionTemplate;
然后,您将实体保存在一个事务中:
@Test
public void validateQueries() {
try {
transactionTemplate.execute((TransactionCallback<Void>) transactionStatus -> {
TestObject testObject = new TestObject(1L);
repository.save(testObject);
return null;
});
} catch (TransactionException e) {
LOGGER.error("Failure", e);
}
SQLStatementCountValidator.reset();
repository.findOne(1L);
SQLStatementCountValidator.assertSelectCount(1);
}
您可以在基本 class 方法中提取事务处理逻辑以简化异常处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.