Spring Boot升级后@Query多列查询抛出IndexOutOfBoundsException问题
问题分析与解决:Spring Boot升级后多列Tuple查询抛IndexOutOfBoundsException
问题场景
将Spring Boot从1.5.2.RELEASE升级到1.5.22.RELEASE后,执行以下多列查询的Spring Data JPA方法时,会抛出IndexOutOfBoundsException: Index: 0, Size: 0异常:
@Transactional(readOnly = true) @Query(value = "SELECT q.id as someId, q.name as someName from Quote q where q.id in (:quoteIds)") List<Tuple> selectSomeThings(@Param("quoteIds") List<Long> quoteIds)
但仅查询单列时(如下两种写法),查询可正常运行:
@Transactional(readOnly = true) @Query(value = "SELECT q.id as someId from Quote q where q.id in (:quoteIds)") List<Tuple> selectSomeThings(@Param("quoteIds") List<Long> quoteIds)
@Transactional(readOnly = true) @Query(value = "SELECT q.name as someName from Quote q where q.id in (:quoteIds)") List<Tuple> selectSomeThings(@Param("quoteIds") List<Long> quoteIds)
可能原因
Spring Boot 1.5.x版本升级时,附带的Hibernate或Spring Data JPA版本同步更新,Tuple的映射逻辑发生了调整。当查询结果为空时,多列Tuple的映射逻辑尝试访问索引0的元素,但结果集为空,从而触发索引越界异常;而单列查询时,框架做了特殊兼容处理,避免了该问题。另外,如果传入的quoteIds是空列表,生成的SQL会包含where q.id in ()这种非法语句,也会加剧异常触发。
解决方案
方案1:改用自定义DTO接收查询结果
创建对应结果结构的DTO类(构造方法参数顺序要和查询列顺序一致):
public class QuoteDto { private Long someId; private String someName; public QuoteDto(Long someId, String someName) { this.someId = someId; this.someName = someName; } // 按需添加getter/setter }
修改查询方法,使用DTO构造查询结果:
@Transactional(readOnly = true) @Query(value = "SELECT new com.yourpackage.QuoteDto(q.id, q.name) from Quote q where q.id in (:quoteIds)") List<QuoteDto> selectSomeThings(@Param("quoteIds") List<Long> quoteIds)
方案2:用Object[]替代Tuple接收结果
将返回类型改为List<Object[]>,手动处理结果数组:
@Transactional(readOnly = true) @Query(value = "SELECT q.id as someId, q.name as someName from Quote q where q.id in (:quoteIds)") List<Object[]> selectSomeThings(@Param("quoteIds") List<Long> quoteIds)
调用时转换数据:
List<Object[]> results = selectSomeThings(quoteIds); for (Object[] row : results) { Long id = (Long) row[0]; String name = (String) row[1]; // 业务逻辑处理 }
方案3:提前校验空参数
在调用查询方法前,先检查quoteIds是否为空,避免生成非法SQL并触发异常:
// 调用处逻辑 if (quoteIds == null || quoteIds.isEmpty()) { return Collections.emptyList(); } List<Tuple> result = quoteRepository.selectSomeThings(quoteIds);
内容的提问来源于stack exchange,提问作者Rey Libutan
相关产品推荐
相关产品推荐

