使用ParallelStream处理Hibernate懒加载实体触发JdbcValuesSourceProcessingState异常求助
问题解决思路
异常原因
你遇到的Illegal pop() with non-matching JdbcValuesSourceProcessingState异常,核心原因是Hibernate Session线程不安全:
Project实体中outputs是懒加载关联,调用project.getOutputs()时需要从当前线程绑定的Hibernate Session中获取数据parallelStream会启用多线程处理,这些工作线程并没有绑定原请求线程的Session,导致懒加载操作时Hibernate内部状态混乱,触发异常
解决方案
1. 提前加载关联数据(最优方案)
直接在查询Project时一次性加载关联的Output,避免后续懒加载操作依赖Session。修改Repository接口,添加带fetch join的查询:
public interface ProjectRepository extends JpaRepository<Project, Long> { @Query("SELECT p FROM Project p JOIN FETCH p.outputs") List<Project> findAllWithOutputs(); }
业务代码中使用该方法获取数据,此时所有Project和对应的Output已加载到内存,后续用parallelStream处理不再依赖Session:
List<Project> projects = projectRepository.findAllWithOutputs(); // 用ConcurrentHashMap的keySet替代synchronizedSet,并发性能更优 Set<SearchOutput> searchOutputs = ConcurrentHashMap.newKeySet(); projects.parallelStream().forEach(project -> { project.getOutputs().forEach(output -> { SearchOutput searchOutput = new SearchOutput( project.getId(), output.getPath(), output.getName(), false ); searchOutputs.add(searchOutput); }); });
2. 改用急加载(可选)
如果业务场景允许,可直接将outputs关联改为急加载:
@OneToMany(mappedBy = "project", fetch = FetchType.EAGER) private List<Output> outputs;
不过这种方式灵活性差,即使不需要关联数据也会强制加载,可能浪费性能,更推荐第一种方案。
额外优化点
- 避免使用
Collections.synchronizedSet(new HashSet<>()),改用ConcurrentHashMap.newKeySet(),并发场景下性能更高 - 若数据量远超5万,可考虑分页查询分批处理,避免内存占用过高
内容的提问来源于stack exchange,提问作者Fernando Schotten
相关产品推荐
相关产品推荐

