使用JPA和Hibernate测试期间检测N + 1查询问题

问题描述 投票:1回答:1

我们正在使用https://github.com/vladmihalcea/db-util,这是一个很棒的工具,但是我们面临着有关会话缓存的挑战,正如另一个问题中提到的那样,它是can't be disabled

因此,以下测试失败,因为findOne从会话缓存中获取对象:

    @Test
    public void validateQueries() {
        // when (scenario definition)
        TestObject testObject = new TestObject(1L);
        repository.save(testObject);
        SQLStatementCountValidator.reset();

        repository.findOne(1L);
        SQLStatementCountValidator.assertSelectCount(1);
    }

每次调用entityManager.clear()时都有一种解决方法,调用SQLStatementCountValidator.reset()

现在,解决方法很好,但容易出错,因为现在我们必须注入EntityManager作为测试的依赖项,并记住在保存了代表我们场景的所有对象后调用entityManager.clear()

问题

  1. 实现此目标的最佳方法是什么?
  2. 您希望SQLStatementCountValidator也清除entityManager吗?

这里您可以检查日志语句(最后一个)

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);
    }
java sql hibernate jpa select-n-plus-1
1个回答
1
投票

交易处理

每个测试都应管理交易。因此,您应该删除在类级别添加的@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);
}

您可以在基类方法中提取事务处理逻辑,以简化异常处理。

热门问题
推荐问题
最新问题