Spring Data JPA 3.0.0+Hibernate 6.1.5中IN子句自定义查询二次执行失败
解决Spring Data JPA 3.0.0 + Hibernate 6.1.5中IN子句查询二次执行AssertionError问题
针对你遇到的问题——使用Querydsl生成带IN子句的自定义查询,首次执行正常、二次执行抛出java.lang.AssertionError,且升级Spring版本无效,以下是排查思路和解决方案:
可能的原因
- Hibernate 6.1.x的参数绑定机制存在状态残留bug:二次执行查询时,Hibernate没有正确重置IN子句的参数上下文,导致断言失败。
- Querydsl与Hibernate 6.1.x的适配兼容性问题:Spring Data JPA 3.0.x搭配的Querydsl版本和Hibernate 6.1.x的参数处理逻辑冲突,重复执行时触发异常。
解决方案
1. 每次执行查询时重新构建Querydsl实例
不要复用类级别的Querydsl查询对象,避免参数状态残留。每次查询都在方法内新建查询实例:
// 错误写法:复用全局查询实例 private final QUser qUser = QUser.user; private final JPAQuery<User> query = new JPAQuery<>(entityManager); public List<User> getUsersByIds(List<Long> ids) { return query.select(qUser).from(qUser).where(qUser.id.in(ids)).fetch(); } // 正确写法:每次新建查询实例 public List<User> getUsersByIds(List<Long> ids) { QUser qUser = QUser.user; return new JPAQuery<>(entityManager) .select(qUser) .from(qUser) .where(qUser.id.in(ids)) .fetch(); }
2. 替换为Spring Data JPA的@Query注解查询
绕过Querydsl的生成逻辑,直接用JPQL写IN子句查询,避免适配问题:
@Repository public interface UserRepository extends JpaRepository<User, Long> { @Query("SELECT u FROM User u WHERE u.id IN :ids") List<User> findByIds(@Param("ids") List<Long> ids); }
3. 降级Hibernate版本到6.0.x
Hibernate 6.1.x系列可能存在未修复的参数绑定bug,暂时降级到兼容Spring Data JPA 3.0.x的6.0.2.Final版本:
<!-- Maven依赖调整示例 --> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <version>6.0.2.Final</version> </dependency>
4. 显式清理Hibernate会话上下文
在查询执行后调用entityManager.clear()清理会话中的参数缓存,但注意这会清除会话内所有持久化对象,需根据业务场景判断是否适用:
public List<User> getUsersByIds(List<Long> ids) { try { QUser qUser = QUser.user; return new JPAQuery<>(entityManager) .select(qUser) .from(qUser) .where(qUser.id.in(ids)) .fetch(); } finally { entityManager.clear(); } }
内容的提问来源于stack exchange,提问作者Sharath Prakash
相关产品推荐
相关产品推荐

