问题现象:使用Mybatis写了一段SQL,数据库可以查询出来,但是通过代码查却为null。
解决方法 :ShardingJDBC不支持子查询,可以改写为join形式
排查过程
环境:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
经过测试,发现MybatisPlus自带的selectById可以获取到结果,但是执行自己写的SQL却返回null.
所以写两个测试接口来方便调试 ,都打上断点
经过我不断的进行两个请求交替的调试,最终定位到关键代码。
org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.lang.String)
方法名 getRowValue 就能看出意思,这个方法做的事情就是获取到一行值
图中的关键字段: foundValues, 在正常能够获取到值的请求时,foundValues 为 true,但是自己写的那条SQL这个变量却为false。
问题定位在了这个变量,为什么他是fasle?
好吧,点进方法继续研究。
过程太长了就忽略掉,后面又定位到关键的一处代码
org.apache.shardingsphere.sql.parser.binder.segment.select.projection.engine.ProjectionsContextEngine#projectionEngine
为什么 projectionEngine 为空呢?
发现赋值的地方是在构造器内
进入关键方法
org.apache.shardingsphere.sql.parser.binder.segment.select.projection.engine.ProjectionsContextEngine#getProjections
进来这个方法看看
问题已经显而易见了
传进来的segment的实际类为SubQuery..., 但是这一堆if判断里,没有能处理的。
所以最终走动了最后的return , 所以返回了empty。
好吧,最后修改下SQL,改为了以下形式
经过测试,数据已经能够正常返回了