You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring+Hibernate+H2单元测试:保存实体后SQL查询无结果排查

Spring+Hibernate+H2单元测试:保存实体后JDBC查询无结果的解决办法

核心原因

测试方法标注了@Transactional,Spring Test默认会在测试结束后回滚事务;同时Hibernate的save操作仅将实体存入一级缓存,未触发数据库同步(除非手动刷新)。你用JDBC直接查询数据库物理数据,自然读不到未提交的事务内数据。另外,multiTenantConnectionProvider.getAnyConnection()可能获取了与当前事务不同的数据库连接,不同连接在默认隔离级别(READ COMMITTED)下无法读取未提交数据。

解决办法

方法1:用Repository查询替代原生JDBC(推荐)

直接通过Spring Data Repository查询,利用Hibernate一级缓存,无需提交事务即可验证数据,同时保持测试隔离性:

// ... 保存代码 ...
reportDTO = reportService.submit(reportDTO);
// 通过Repository查询验证
Optional<ReportEntity> savedReport = reportRepository.findById(reportDTO.getId());
System.out.println(savedReport.get().getText());

方法2:获取当前事务的数据库连接

注入DataSource,通过Spring工具类获取当前事务使用的连接,这样能读到未提交的事务数据:

@Autowired
private DataSource dataSource;

// ... 测试代码 ...
reportDTO = reportService.submit(reportDTO);
// 获取当前事务的连接
Connection connection = DataSourceUtils.getConnection(dataSource);
String sql = "select * from PUBLIC.report";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);

while (resultSet.next()) {
  String text = resultSet.getString("text");
  System.out.println(text);
}

方法3:强制提交事务(谨慎使用)

在测试方法上添加@Commit注解,让Spring Test执行完测试后提交事务,而非回滚:

@Transactional
@Commit
@Test
void test_OptimisticLockExceptionOnUpdate() throws SQLException {
    // ... 原有代码 ...
}

注意:这种方式会在数据库中残留测试数据,需确保测试后清理数据,避免影响其他测试。

方法4:手动刷新Hibernate会话

注入EntityManager,手动刷新会话将缓存数据同步到数据库,无需提交事务即可让同一连接读到数据:

@Autowired
private EntityManager entityManager;

// ... 测试代码 ...
reportDTO = reportService.submit(reportDTO);
// 刷新会话,同步缓存到数据库
entityManager.flush();
// 后续JDBC查询代码不变

内容的提问来源于stack exchange,提问作者bobbyrne01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:01:00