项目场景:
学习springboot整合mybatis-plus时通过构建器执行相关操作
@Autowired BookMapper mapper; @Test void test(){ QueryWrapper<Book> wrapper = new QueryWrapper<>(); wrapper .select("id", "name", "press") //只查询前三个字段 .gt("id", 1 ) //只要id>1的列 .like("name","%计算机%"); //名字中有计算机的 System.out.println(mapper.selectList(wrapper)); }
问题描述
控制台出现索引越界异常
### Error querying database. Cause: java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3
### The error may exist in com/lmw/mapper/BookMapper.java (best guess)
### The error may involve com.lmw.mapper.BookMapper.selectList
### The error occurred while handling results
### SQL: SELECT id,name,press FROM tb_book WHERE (id > ? AND name LIKE ?)
### Cause: java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:156)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:425)
... 11 more
此时将构建器中的select条件去掉,竟然执行成功了
原因分析:
查看控制台的SQL日志
Preparing: SELECT id,name,press,author FROM tb_book WHERE (id > ? AND name LIKE ?)
如果去掉 select() 就是查询全部列(成功),不去掉就是查询指定列(报错)
分析代码执行流程:传入构建器wrapper--构建SQL语句--生成对应筛选where条件--返回select指定列数据--封装成实体类对象--输出
因此可以判断问题出在 select返回指定列数据--封装成实体类对象 这一步
然而这一步骤是通过调用实体类的构造方法完成的,此时我们进入实体类查看:
可以注意到类名上面打上了 @AllArgsConstructor 注解,该注解的作用相当于为这个类指定了一个全字段构造方法,到这里报错的原因大概就能知道了
由于我们指定了一个全字段的构造方法,且并没有其他无参或有参的构造方法,那么在mybatis-plus替我们封装数据的时候就会出问题:我们只拿到了其中的几列数据,但构造器要求我们提供所有的字段数据,自然就报错了。至于为什么是索引越界异常,我的猜想:
mapper执行完查询后返回的是一个有序的数据集合,每一个列占一个索引,在封装成对象的时候,调用一个仅有全字段构造方法,此时构造方法会从返回的数据集合中读取相应的字段,读取到一半时,集合中的数据已经读完了,但构造方法还没结束,所以继续往下读,此时便发生了索引越界异常。
纯个人猜想,欢迎指正~
解决方案:
1.去掉@AllArgsConstructor注解,此时会有一个默认的无参构造方法
@Data @TableName("tb_book") //@AllArgsConstructor public class Book { ... }
2.手动加上一个无参构造方法
@Data @TableName("tb_book") @AllArgsConstructor public class Book { public Book(){ } ... }
测试运行,可以看到两种方法都执行成功了
标签:java,构造方法,--,DefaultSqlSession,ibatis,apache,org,id,### From: https://blog.csdn.net/laiminwei/article/details/136783479