导火索
最近碰到了一个很诡异的问题,通过mybatis
原生的selectList
正常查询数据库,结果mybatis
报了一个indexOutOfBoundsException
的异常,百思不得其解,为啥查询会导致索引越界呢?
主要原因就在于lombok
的一个注解@Builder
,以及@TableField(exist=false)
,导致查询后回填数据到实体异常
原因
读了一下mybatis源码,主要起因是DefaultResultSetHandler
类中的createResultObject
方法,里面有一堆条件判断,主要是最后两个条件判断,当类有默认构造器与没有默认构造器执行的逻辑是不一样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 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); } if (!constructorMappings.isEmpty()) { return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix); } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) { return objectFactory.create(resultType); } else if (shouldApplyAutomaticMappings(resultMap, false)) { return createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes, constructorArgs); } throw new ExecutorException("Do not know how to create an instance of " + resultType); }
|
createByConstructorSignature
方法跟进去就能看到真正报错的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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; }
|
因为rsw.getColumnNames
拿到的是实体对应表的字段数量,而constructor.getParameterTypes().length
拿到的是实体全字段的数量(其中包括了@TableField(exist=false)
修饰的字段),所以导致get(i)
的越界而抛出indexOutOfBoundsException
的异常
结论
我碰到的是这种情况,但是我在网上并没有找到原因,网文只是告诉你加上无参的构造器就行,而并没有分析源码解释问题,很多时候原因比答案更重要
本文作者:oldmee
本文链接:https://oldmee.github.io/2020/09/06/mybatis-indexOutOfBoundsException/
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。