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
相关产品推荐
相关产品推荐

