首页 专题 文章 代码 归档
Mybatis的动态SQL
2020.02.06 14:14 2020.02.06 14:14

1. 动态SQL

标签:

• if

• choose (when, otherwise)

• trim (where, set)

• foreach

1.1. if标签和where标签

场景:以员工的bean类查询,有哪个属性,就查询哪个字段。

标签:<if test=""></if>

支持NGEL表达式,基本用法:

截图-1580900749

代码:

mapper:

<select id="findByEm" resultType="employee">
    select *
    from employee
    where
    <if test="id!=null">
        id = #{id}
    </if>
    <if test="email!=null">
        and email = #{email}
    </if>
    <if test="gender!=null">
        and gender = #{gender}
    </if>
</select>

测试:

@Test
public void testDynamic() throws IOException {
    SqlSession sqlSession = getSqlSession();

    EmployeeDynamicSql mapper = sqlSession.getMapper(EmployeeDynamicSql.class);
    Employee employee = new Employee();
    employee.setId(5);
    employee.setGender("男");
    Employee byEm = mapper.findByEm(employee);
    System.out.println("byEm = " + byEm);

    sqlSession.commit();
}

没有问题:

截图-1580901109

但是,如果把employee.setId(5);去掉的话,就有问题了。

为什么?因为在mapper中,我们如过没有id的后,后面接着的是

<if test="email!=null">
    and email = #{email}
</if>

SQL语句成了:

select * from employee where and gender = ?

where后面直接多了个and


解决办法:

1、where后面直接跟一个1=1,即:

<select id="findByEm" resultType="employee">
    select *
    from employee
    where 1=1
    <if test="id!=null">
        id = #{id}
    </if>
    <if test="email!=null">
        and email = #{email}
    </if>
    <if test="gender!=null">
        and gender = #{gender}
    </if>
</select>

2、将所有if标签,放进where标签:

<select id="findByEm" resultType="employee">
    select *
    from employee
    <where>

        <if test="id!=null">
            id = #{id}
        </if>
        <if test="email!=null">
            and email = #{email}
        </if>
        <if test="gender!=null">
            and gender = #{gender}
        </if>
    </where>
</select>

但是,where只会去掉第一个多出某的and或者or

即:

<where>

    <if test="id!=null">
       and id = #{id}
    </if>
</where>

可以,但是:

<where>

    <if test="id!=null">
        id = #{id} and
    </if>
</where>

不可以!

1.2. trim标签

如下,and/or写在后面,那么都不好使:

<select id="findByEmByTrim" resultType="employee">
    select *
    from employee
    <if test="id!=null">
        id = #{id}
    </if>
    <if test="email!=null">
        email = #{email} and
    </if>
    <if test="gender!=null">
        gender = #{gender} and
    </if>
</select>

这时就可以使用<trim>

属性:

  • prefix:在整体前面加一个字符串
  • prefixOverrides:在整体前面去掉一个字符串
  • suffix:在整体后面....
  • suffixOverrides:在整体后面....

比如下面这个mapper:在前面加一个where,去掉最后一个and标签

<select id="findByEmByTrim" resultType="employee">
    select *
    from employee
    <trim prefix="where" suffixOverrides="and">
        <if test="id!=null">
            id = #{id} and
        </if>
        <if test="email!=null">
            email = #{email} and
        </if>
        <if test="gender!=null">
            gender = #{gender} and
        </if>
    </trim>
</select>

1.3. set标签

set标签用于修改,和where标签类似,用于删除多余的,

mapper:

<update id="updateByAny">
    update employee
    <set>
        <if test="lastName!=null">
            last_name=#{lastName},
        </if>
        <if test="email!=null">
            email=#{email},
        </if>
    </set>
    where id=#{id}

</update>

1.4. choose标签

也即类似java中的switch-case

场景:如果带有id就按id查,如果带有email就按email查:

mapper:

<select id="findByIdOrEmail" resultType="employee">
    select *
    from employee
    <where>
        <choose>
            <when test="id!=null">
                id=#{id}
            </when>
            <when test="email!=null">
                email=#{email}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </where>
</select>

1.5. foreach标签

循环取出元素,foreach元素的属性主要有item,index,collection,open,separator,close。

  • item:集合中元素迭代时的别名,该参数为必选。
  • index:在list和数组中,index是元素的序号,在map中,index是元素的key,该参数可选
  • open:foreach代码的开始符号,一般是(和close=")"合用。常用在in(),values()时。该参数可选
  • separator:元素之间的分隔符,例如在in()的时候,separator=","会自动在元素中间用“,“隔开,避免手动输入逗号导致sql错误,如in(1,2,)这样。该参数可选。
  • close: foreach代码的关闭符号,一般是)和open="("合用。常用在in(),values()时。该参数可选。
  • collection: 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键,Map对象没有默认的键。当然在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = "ids".如果User有属性Ids ids;其中Ids是个对象,Ids有个属性List id;入参是User对象,那么collection = "ids.id"

实例代码:

接口:

public List<Employee> findByForeach(List<Integer> ids);

mapper:

<select id="findByForeach" resultType="com.misiai.bean.Employee">
    select *
    from employee
    where id in
    <foreach collection="list" separator="," open="(" close=")" item="item_id" index="i">
        #{item_id}
    </foreach>
</select>

解释:

1、上面mapper生成的 语句是:

select * from employee where id in 

也就是说,foreach标签生成了:( ? , ? )

测试代码:

List<Employee> byForeach = mapper.findByForeach(Arrays.asList(5, 6));
for (Employee foreach : byForeach) {
    System.out.println("foreach = " + foreach);
}

1.6. 内置参数

Mybatis中内置了两个参数:_parameter_databaseId

  • _parameter
    • 如果单个参数,那么_parameter就是这个参数
    • 如果多个参数,会被封装成一个map,_parameter就是代表这个map
  • _databaseId
    • 如果配置了databaseIdProvider标签, _databaseId就是代表当前数据库的别名,mysql或者oracle等等。

1.7. bind标签

bind:可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值

例如进行模糊查询!

<select id="findByLike" resultType="employee">
    <bind name="_lastName" value="'%'+lastName+'%'"/>
    select * from employee where last_name like #{_lastName};
</select>

生成的SQL语句:

select * from employee where last_name like ?;

这样就保证了不被注入,用的是#{xxxx}取的值。

1.8. sql标签和include标签

抽取可重用的sql片段。方便后面引用。

<sql id="commonSql">
    select *
    from employee
</sql>

<select id="findByLike" resultType="employee">
    <bind name="_lastName" value="'%'+lastName+'%'"/>
    <include refid="commonSql"/>
    where last_name like #{_lastName};
</select>

sql标签中可自定义任何SQL语句片段,然后在需要的西方,用include标签引入即可。

本节阅读完毕!
二维码图片 扫描关注我们哟