数据库最后一个字段Null导致mybatis抛出异常ArrayIndexOutOfBoundsException
mybatis抛出异常ArrayIndexOutOfBoundsException
项目框架
Spring boot1.5.9 + mybatis3 + mysql-conector-java 6.0.6
出错原因
查询表返回的记录中最后一个字段值是null,mybatis组装pojo失败,会抛出ArrayIndexOutOfBoundsException异常。如果通过错误栈发现,实际是mysql驱动mysql-conector-java在BinaryBufferRow.getValue这个方法中最先抛出的。跟踪源码发现,在获取最后一个字段值时,由于是null值,错误的走了readInteger方法
public <T> T getValue(int columnIndex, ValueFactory<T> vf)
{
findAndSeekToOffset(columnIndex);
int type = this.metadata.getFields()[columnIndex].getMysqlTypeId();
int length = MysqlaUtils.getBinaryEncodedLength(type);
if (length == 0) //最后一个字段是Null,长度为0,走了if分支中。
length = (int)this.rowFromServer.readInteger(NativeProtocol.IntegerDataType.INT_LENENC);
else if (length == -1) {
throw ExceptionFactory.createException(Messages.getString("MysqlIO.97", new Object[] { Integer.valueOf(type), Integer.valueOf(columnIndex + 1), Integer.valueOf(this.metadata.getFields().length) }), this.exceptionInterceptor);
}
return getValueFromBytes(columnIndex, this.rowFromServer.getByteBuffer(), this.rowFromServer.getPosition(), length, vf);
}
去maven库查了最新的驱动版本8(8.x版本),发现已修改这个问题:
public <T> T getValue(int columnIndex, ValueFactory<T> vf) {
this.findAndSeekToOffset(columnIndex);
int type = this.metadata.getFields()[columnIndex].getMysqlTypeId();
int length = NativeUtils.getBinaryEncodedLength(type);
if(!this.getNull(columnIndex)) { //主要是多了这行,预先判断了是否Null值,如果是,则走getValueFromBytes方法。
if(length == 0) {
length = (int)this.rowFromServer.readInteger(IntegerDataType.INT_LENENC);
} else if(length == -1) {
throw ExceptionFactory.createException(Messages.getString("MysqlIO.97", new Object[]{Integer.valueOf(type), Integer.valueOf(columnIndex + 1), Integer.valueOf(this.metadata.getFields().length)}), this.exceptionInterceptor);
}
}
return this.getValueFromBytes(columnIndex, this.rowFromServer.getByteBuffer(), this.rowFromServer.getPosition(), length, vf);
}
解决方法
- 升级mysql驱动,我之前是6.0.6,升到最新版本8.x.x
- 代码中人为控制最后一列记录不要为NULL。
第一种简单快捷,一劳永逸。缺点是对项目的影响最大,可能有新的坑要踩。
第二种改了不影响项目其它代码,缺点是改动量大,还有可能会漏改。