使用 mybatisplus的 LambdaQueryChainWrapper报错
RegionPO one = new LambdaQueryChainWrapper<>(regionDAO) .select(RegionPO::getRegionId) .eq(RegionPO::getName, "广东省") .one();
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 com/yhd/open/content/management/dao/RegionDAO.java (best guess) ### The error may involve com.yhd.open.content.management.dao.RegionDAO.selectList ### The error occurred while handling results ### SQL: SELECT region_id FROM region WHERE (`name` = ?) ### Cause: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) at com.sun.proxy.$Proxy210.selectList(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) 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.$Proxy211.selectList(Unknown Source) at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:173) at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) at com.sun.proxy.$Proxy211.selectOne(Unknown Source) at com.baomidou.mybatisplus.extension.conditions.query.ChainQuery.one(ChainQuery.java:48) ........................
是因为RegionPO对象(也就是接受对象)没有无参构造,而写了个全参构造在里面,错误代码:
只需要把@AllArgsConstructor去掉即可,因为写了@AllArgsConstructor当前对象就不会有无参构造
1、索引越界异常就很奇怪,一开始下意识以为是one的问题:
但当我改成list时也还是一样报错
mybatis的sql日志
JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@6329e680] will not be managed by Spring ==> Preparing: SELECT region_id FROM region WHERE (`name` = ?) ==> Parameters: 广东省(String) <== Columns: region_id <== Row: 44 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@17826d60]
从上面日志得知结果已经查询出来,证明sql是没有问题的,那就一定是给对象赋值的时候有问题了
在 MyBatis-Plus 源码中, LambdaQueryChainWrapper 类是 MyBatis-Plus 提供的链式查询的入口类,它并不直接负责将查询结果设值到实体对象中。实际上,查询结果的设值是由 MyBatis 的 ResultSetHandler 完成的。
具体来说,当执行 LambdaQueryChainWrapper 的查询方法(如 list() 、 getOne() 等)时,它会将查询条件封装成一个 MappedStatement 对象,并通过 MyBatis 的 SqlSession 进行查询操作。查询结果会由 MyBatis 的 ResultSetHandler 进行处理,将查询结果映射到实体对象中。
在 MyBatis 的 ResultSetHandler 实现类中,常用的实现是 DefaultResultSetHandler 。它会调用 ObjectFactory 创建实体对象,并通过 MetaObject 对象将查询结果设值到实体对象的属性中。
总结起来,在 MyBatis-Plus 中, LambdaQueryChainWrapper 类负责构建查询条件链式调用,而查询结果的设值是由 MyBatis 的 ResultSetHandler 实现类完成的。具体的设值过程涉及到 MyBatis 的对象工厂、元对象和反射等机制。
1、由上面可知赋值在DefaultResultSetHandler类
debug到这一步一步执行,我们可以发现是在createResultObject()方法发生异常的,进到此方法内部:
2、DefaultResultSetHandler.createResultObject.createResultObject
进入这里,当有无参构造时会进入上一个if语句
metaType.hasDefaultConstructor() //判断是否有无参构造
3、进入createByConstructorSignature —>applyConstructorAutomapping方法
configuration.isArgNameBasedConstructorAutoMapping()//判断是否基于Arg名称的构造函数自动映射,都没有无参构造当然不是所以进入else里面的applyColumnOrderBasedConstructorAutomapping方法
4、进入applyColumnOrderBasedConstructorAutomapping方法(最终报错点)
最终是在第二次允许这个for循环时String columnName = rsw.getColumnNames().get(i);报索引超出异常
我们可以运行constructor.getParameterTypes()方法,得到的是你赋值对象每个属性的属性类型
但我们运行rsw.getColumnNames()时,结果是只有你查询的字段:
还记得我们最开始的语句吗:
RegionPO one = new LambdaQueryChainWrapper<>(regionDAO) .select(RegionPO::getRegionId) .eq(RegionPO::getName, "广东省") .one();
从这里我们可以看出rsw.getColumnNames()是拿到你需要查询的字段,所以按照这个逻辑,当我们查询所有字段的时候就不会报错!!
事实也跟我想的一样,确实查所有就不会报错!!
4、当我们对象有无参构造时他的赋值则是:
由createResultObject创建了一个所有属性都是null的对象,也就是new了一个无参构造一样
然后来到createResultObject的调用方getRowValue方法
applyAutomaticMappings
我相信很多人看到这个代码都有种很熟悉的感觉,很像原生的JDBC
createAutomaticMappings() 构建映射条件,也就是数据库表字段和对象属性对应,会根据你所查询的字段构建
final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column); 这行代码是根据字段名找到对应结果集中的value
metaObject.setValue(mapping.property, value); 赋值
当对象没有无参构造,而有全参构造时,mybatis是根据对象的所有属性来遍历赋值的
而当对象有无参构造时:则是根据查询字段来赋值
上一篇:Nginx超时配置