背景 
1.1 一个SQL查询 比如下面的

    <sql id="selectCount">
        select count(*) from `user`
        <where>
            <if test="names != null and names.size > 0">
                name in (
                   <foreach collection="names" item="name" separator=",">
                       #{name}
                   </foreach>
                )
            </if>
            <if test="name != null">
                name = #{name}
            </if>
        </where> 
    </sql>

1.2  UserMapper

@Mapper
public
interface UserMapper { int selectCount(Map<String,Object> param);

}

1.3 查询

@SpringbootApplication
public class Application {
     
     @Autowired
     UserMapper userMapper;

    @Test
    public  void test() {
     
     Map<String,Object> param =  new HashMap<>();
param.put('names', Lists.newArrayList('张三','李四','王五')); userMapper.selectCount(param);

// 1. 期望执行的SQL: select count(*) from `user` where name in (
'张三','李四','王五');
// 2. 结果执行的SQL: select count(*) from `user` where name in ('张三','李四','王五') and name = '王五';
) } }

2. 如何修改

   2. 1  调整SQL (第一种方案: foreach 部分放在下面; 第二种方案: foreach的 item 属性不与下方的参数相同 如使用  'nameTemp')

    <sql id="selectCount">
        select count(*) from `user`
        <where>
            <if test="name != null">
                name = #{name}
            </if>
<if test="names != null and names.size > 0"> name in ( <foreach collection="names" item="name" separator=","> #{name} </foreach> ) </if> </where> </sql>

  2. 2  升级mybaits 版本 3.5

 

3.  原因简说

    1. mybatis在组装动态SQL时将方法所有的参数转为map,  解析每个动态SQL节点的时,会将这些参数替换进去。

   2. 当解析foreach节点时,由于item 属性的存在,会将item也做作为参数放在map里,当解析后续的动态SQL时,就导致使用到item属性。  而高版本的mybaits 是  当解析完一个foreach动态SQL节点会移除这些组装过的属性。就不存在item会影响后面的动态SQL节点;

   

   主要涉及代码类: org.apache.ibatis.scripting.xmltags.DynamicContext;   org.apache.ibatis.scripting.xmltags.ForEachSqlNode#apply(DynamicContext context)

)

                 

             

posted on 2021-03-26 11:32  yang希军  阅读(127)  评论(0)    收藏  举报