使用Mybatis中执行如下查询:
单元测试
XML
打印的SQL:
Mybatis版本
这是公司的老项目,在迭代的过程中遇到了此问题,以此记录!
PS: 此bug在mybatis-3.4.5版本中已经解决。并且Mybatis维护者也建议不要在item/index中使用重复的变量名。
入口,跟着build方法走
来到SqlSessionFactoryBuilder#build方法
跟着parse方法走,来到XMLConfigBuilder#parseConfiguration方法
来到mapperElement方法
XMLMapperBuilder类,负责解析SQL语句所在XML中的内容
XMLStatementBuilder负责解析单个select|insert|update|delete节点
由上文可知,此处的SqlSessionFactory使用的是DefaultSqlSessionFactory
这里获取到了一个DefaultSqlSession对象
获取CommonMapper的对象,这里CommonMapper是一个接口,因此是一个代理对象,代理类是MapperProxy
执行Query方法,来到MapperProxy的invoke方法
执行操作时,根据SELECT操作,以及返回值类型(反射方法获取)确定executeForMany方法
来到executeForMany方法中,就可以看到执行查询的操作,由于这里没有进行分页查询,因此走else
来到DefaultSqlSession#selectList方法中
CachingExecutor#query
MappedStatement#getBoundSql
由上文,此次语句由于SQL中包含元素节点,因此是DynamicSqlSource。由此来到DynamicSqlSource#getBoundSql。
rootSqlNode.apply(context);这段代码便是在执行SQL解析。
打上断点,跟着解析流程,来到解析foreach标签的代码,ForEachSqlNode#apply
到这里,结果就清晰了,在解析foreach标签时,每次循环都会将item属性值与参数集合中的值进行绑定,到最后就会保留(width:3)的映射关系,而在解析完foreach标签后,会解析最后一个if标签,此时在判断if标签是否成立时,答案是true,因此最终拼接出来一个错误的SQL。
在3.4.5版本中,代码中增加了
context.getBindings().remove(item);在foreach标签解析完成后移除bindings中的参数映射。以下是源码:
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70000430/viewspace-2783586/ ,如需转载,请注明出处,否则将追究法律责任。