使用MyBatis时出现java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

一、出现情况和解决方法

  • 报错信息
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
### The error may exist in file [C:\Users\56342\Desktop\irest\irest-reports\irest-reports-server\target\classes\com\shht\irest\reports\server\mapper\oms\xml\OrderTransactionMapper.xml]
### The error may involve com.shht.irest.reports.server.mapper.oms.OrderTransactionMapper.countConsumeCount
### The error occurred while handling results
### SQL: SELECT         COUNT(DISTINCT(ot.id)) as `count`         FROM         oms_order_transaction ot         JOIN         oms_order_transaction_detail otd ON ot.id = otd.transaction_id         WHERE         ot.tenant_id = 1         AND ot.pay_time BETWEEN ? AND ?         AND ot.type = 'CONSUME' and ot.state = 'SUCCESS' AND ot.delete_flag = 0                       AND otd.merchant_id = ?
### Cause: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
	at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:440)
	at com.sun.proxy.$Proxy124.selectOne(Unknown Source)
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:159)
	at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:90)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148)
	at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
	at com.sun.proxy.$Proxy128.countConsumeCount(Unknown Source)
  • XML的SQL语句
SELECT
COUNT(DISTINCT(ot.id)) as `count`
FROM
oms_order_transaction ot
JOIN
oms_order_transaction_detail otd ON ot.id = otd.transaction_id

出现场景:在使用MyBatis进行SQL查询的时候,会抛出异常java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
出现原因:项目中Mapper查询结果映射的Result实体类没有提供无参构造器
解决方法:映射的实体类加上@NoArgsConstructor

@Data
@NoArgsConstructor
public class OrderTransactionMerchantSalesVO implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "统计日期(日/月)")
    private Date statisDate;

    @ApiModelProperty(value = "统计日期(日/月)")
    private String staticsDateText;

    @ApiModelProperty(value = "商户ID")
    private Long merchantId;

    @ExcelProperty(value = "商户名称", index = 1)
    @ApiModelProperty(value = "商户名称")
    private String merchantName;

    @ApiModelProperty(value = "项目ID")
    private Long projectId;

    @ExcelProperty(value = "所属项目", index = 2)
    @ApiModelProperty(value = "项目名称")
    private String projectName;

    @ExcelProperty(value = "销售数量", index = 3)
    @ApiModelProperty(value = "销量")
    private Integer count;

    @ExcelProperty(value = "营业额", index = 4)
    @ApiModelProperty(value = "营业额")
    private BigDecimal totalAmount;

    @ExcelProperty(value = "充值真实金额实收", index = 5)
    @ApiModelProperty(value = "充值真实金额实收")
    private BigDecimal realAmount;

    @ExcelProperty(value = "充值赠送金额实收", index = 6)
    @ApiModelProperty(value = "充值赠送金额实收")
    private BigDecimal discountAmount;

    @ExcelProperty(value = "补贴实收", index = 7)
    @ApiModelProperty(value = "补贴实收")
    private BigDecimal allowanceAmount;

    @ExcelProperty(value = "微信实收", index = 8)
    @ApiModelProperty(value = "微信实收")
    private BigDecimal weChatAmount;

    @ExcelProperty(value = "支付宝实收", index = 9)
    @ApiModelProperty(value = "支付宝实收")
    private BigDecimal alipayAmount;

    @ExcelProperty(value = "其他实收", index = 10)
    @ApiModelProperty(value = "其他实收")
    private BigDecimal otherAmount;

    @ExcelProperty(value = "消费券实收", index = 11)
    @ApiModelProperty(value = "消费券实收")
    private BigDecimal voucherAmount;

    @ApiModelProperty(value = "充值真实金额实收")
    private BigDecimal actualAmount;

    @ApiModelProperty(value = "平均均销售额")
    private BigDecimal averageAmount;

    @ApiModelProperty(value = "平均销量")
    private BigDecimal averageCount;

    @ApiModelProperty(value = "退单数")
    private Integer refundOrderAmount;

    @ApiModelProperty(value = "手续费")
    private BigDecimal commission;

    public OrderTransactionMerchantSalesVO(Long merchantId, String merchantName) {
        this.merchantId = merchantId;
        this.merchantName = merchantName;
        this.count = 0;
        this.totalAmount = BigDecimal.ZERO;
        this.averageAmount = BigDecimal.ZERO;
        this.averageCount = BigDecimal.ZERO;
        this.refundOrderAmount = 0;
        this.realAmount = BigDecimal.ZERO;
        this.discountAmount = BigDecimal.ZERO;
        this.allowanceAmount = BigDecimal.ZERO;
        this.voucherAmount = BigDecimal.ZERO;
        this.weChatAmount = BigDecimal.ZERO;
        this.alipayAmount = BigDecimal.ZERO;
        this.otherAmount = BigDecimal.ZERO;
        this.actualAmount = BigDecimal.ZERO;
        this.commission = BigDecimal.ZERO;
    }
}

二、源码分析

2.1 出现问题的原因

package org.apache.ibatis.executor.resultset;

public class DefaultResultSetHandler implements ResultSetHandler {
  private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
    boolean foundValues = false;
    for (int i = 0; i < constructor.getParameterTypes().length; i++) {
      Class<?> parameterType = constructor.getParameterTypes()[i];
      String columnName = rsw.getColumnNames().get(i);
      TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
      Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
      constructorArgTypes.add(parameterType);
      constructorArgs.add(value);
      foundValues = value != null || foundValues;
    }
    return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
  }
}

MyBatis在设置相应参数的时候,由于只有一个两参的构造器,此时方法会进行根据构造器的参数进行两次循环。而sql响应结构只有一个参数,因此会报出数组下标越界的异常。Caused by: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
报错后执行handleResultSet()方法中执行代码的finally块的方法

在这里插入图片描述
在这里插入图片描述

2.2 MyBatis选择Constructor的策略

public class DefaultResultSetHandler implements ResultSetHandler {
	
	/**
	 * 构建响应的映射实体类
	 */
  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
      throws SQLException {
    final Class<?> resultType = resultMap.getType();
    final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
    final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
    if (hasTypeHandlerForResultObject(rsw, resultType)) {
      return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
    } else if (!constructorMappings.isEmpty()) {
      return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
	
	// 如果存在无参构造器metaType.hasDefaultConstructor()会返回true
    } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
      return objectFactory.create(resultType);

	// 如果仅配置了带参数的构造器则会进入到该方法中
    } else if (shouldApplyAutomaticMappings(resultMap, false)) {
      return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
    }
    throw new ExecutorException("Do not know how to create an instance of " + resultType);
  }
}
  private Object createByConstructorSignature(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) throws SQLException {
    final Constructor<?>[] constructors = resultType.getDeclaredConstructors();
    // 返回设置的 带参数的构造器
    final Constructor<?> defaultConstructor = findDefaultConstructor(constructors);
    if (defaultConstructor != null) {
      return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, defaultConstructor);
    } else {
      for (Constructor<?> constructor : constructors) {
        if (allowedConstructorUsingTypeHandlers(constructor, rsw.getJdbcTypes())) {
          return createUsingConstructor(rsw, resultType, constructorArgTypes, constructorArgs, constructor);
        }
      }
    }
    throw new ExecutorException("No constructor found in " + resultType.getName() + " matching " + rsw.getClassNames());
  }


  private Constructor<?> findDefaultConstructor(final Constructor<?>[] constructors) {
  	// 如果只有一个构造器那么直接使用。
  	// 所以按照我们上面配置了1个两参构造器的时候,MyBatis会直接默认使用
    if (constructors.length == 1) {
      return constructors[0];
    }

    for (final Constructor<?> constructor : constructors) {
      if (constructor.isAnnotationPresent(AutomapConstructor.class)) {
        return constructor;
      }
    }
    return null;
  }
根据提供的引用内容,报错"java.lang.IndexOutOfBoundsException: Index: 3, Size: 3"是由于下标越界引起的。这个错误通常发生在使用MyBatis查询数据库,查询结果的索引超出了结果集的范围。 为了解决这个问题,你可以检查以下几个方面: 1. 检查SQL语句是否正确:确保你的SQL语句正确无误,没有错误的表名、列名或条件。 2. 检查查询结果是否为空:在使用MyBatis查询数据库,如果查询结果为空,尝试访问结果集中的元素会导致下标越界异常。在使用查询结果之前,可以先判断结果集是否为空。 3. 检查Mapper配置文件:检查Mapper接口对应的XML文件中是否正确映射了数据库表和实体类,以及查询语句是否正确。 4. 检查参数是否正确传递:如果你在查询语句中使用了参数,确保参数正确传递给了MyBatis。 下面是一个使用MyBatis查询一条记录的示例代码: ```java // 定义Mapper接口 public interface UserMapper { User selectUserById(int id); } // 在XML文件中配置查询语句 <select id="selectUserById" resultType="com.example.User"> SELECT * FROM users WHERE id = #{id} </select> // 在Java代码中使用Mapper接口查询一条记录 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.selectUserById(1); ``` 请注意,这只是一个示例代码,具体的实现方式可能因项目而异。你需要根据你的实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值