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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:01:35