【MyBatis】如何使用“动态SQL”(超详解)

目录

前言

动态标签用法

一、if标签

二、where标签

三、trim标签

四、set标签

五、foreach标签

六、choose、when、otherwise标签

七、bind标签

八、include标签


前言

        MyBatis提供了10种动态SQL标签:trim、where、set、foreach、if、choose、when、otherwise、bind、include;其执行原理为,使用OGNL从SQL参数对象中计算表达式的值,根据表达式的值动态拼接SQL,以此来完成动态SQL的功能。

动态标签用法

一、if标签

        通过test属性中的表达式去判断内容是否有效,有效则将if中的sql片段拼接执行。

例如:在人员信息表,根据姓名,年龄,地址,性别等条件查询人员信息。

dao层:

    User sqlUse(@Param("name") String name, @Param("age") int age,
            @Param("address") String address, @Param("sex") String sex);

xml(注释已在代码):

<select id="sqlUse" resultType="com.example.animalhome.web.entity.User">
	    select * from user where
	    <!-- 判断name不为空 -->
	    <if test="name != '' and name != null">
	        name = #{name}
	    </if>
	    <!-- 比较address的写法:equals或者== -->
	    <!-- 若是单个字符串,建议使用此写法(原因在sex使用时会有说明!!!): -->
	    <!-- <if test="address.equals('北'.toString()) or address == '上'.toString()"> -->
	    <if test="address.equals('北京') or address == '上海'">
	        and address = #{address}
	    </if>
	    <!-- 比较age是否大于0且等于19(注意:字段age为int类型)-->   
	    <if test="age > 0 and age == 19">
	        and age = #{age}
	    </if>
	    <!-- sex使用<if test="flag=='1'"></if>这种写法时有风险,-->
	    <!-- 原因:Mybatis是用OGNL表达式来解析的,在OGNL的表达式中,-->
	    <!-- '1'会被解析成字符,java是强类型的,char和一个string会导致不等,-->
	    <!-- 所以if标签中的sql不会被解析,故推荐使用toString()解析成字符串来比较。-->
	    <if test="sex == '1'.toString()">
	        and sex = #{sex}
	    </if>
</select>

操作日志:

        问题:若是上述条件都不满足会出现select * from where...的情况,亦或name条件不满足则会出现select * from where and...的语法错误,导致sql报错无法进行,那么该如何修改sql?

<select id="sqlUse" resultType="com.example.animalhome.web.entity.User">
     select * from user where 1=1
     <if test="name != '' and name != null">
         and name = #{name}
     </if>
     <if test="age > 0 and age == 19">
         and age = #{age}
     </if>
     <if test="sex == '1'.toString()">
         and sex = #{sex}
     </if>
</select>

        解释:只需要在where语句后加上1=1的恒成立条件,并且在每个if的sql前面加上and即可;但是接下来介绍的<where>标签是最优解。

二、where标签

        where标签特性:

  1. 只有if标签有内容的情况下才会拼接where字句;
  2. 若子句的开通为"and"或"or",where标签会将它替换去除。

        需要注意的是:where标签只会智能的去除首个满足条件语句的前缀,所以建议在使用where标签时,每个语句都最好写上 and 前缀或者 or 前缀。否则会出现以下问题:

    <select id="sqlUse" resultType="com.example.animalhome.web.entity.User">
        select * from user
        <where>
            <if test="name != '' and name != null">
                name = #{name}
            </if>
            <if test="age > 0 and age == 19">
                age = #{age}
            </if>
            <if test="sex == '1'.toString()">
                sex = #{sex}
            </if>
        </where>
    </select>

        生成的sql语句如下:

select * from user WHERE name = ? age = ? sex = ?

        很明显,sql语法是有问题的,所以在使用where标签时,建议将所有条件都添加上and或or;正确的使用方法如下:

例如:在人员信息表,根据姓名,年龄,地址,性别等条件查询人员信息。

<select id="sqlUse" resultType="com.example.animalhome.web.entity.User">
        select * from user
        <where>
            <if test="name != '' and name != null">
                and name = #{name}
            </if>
            <if test="age > 0 and age == 19">
                and age = #{age}
            </if>
            <if test="sex == '1'.toString()">
                and sex = #{sex}
            </if>
        </where>
</select>

三、trim标签

        trim标签参数说明:

  1. prefix:给trim标签内sql语句加上前缀
  2. suffix:给trim标签内sql语句加上后缀
  3. prefixOverrides:去除多余的前缀内容,如:prefixOverrides=“OR”,去除trim标签内sql语句多余的前缀"OR"
  4. suffixOverrides:去除多余的后缀内容,如:suffixOverrides=",",去除trim标签内sql语句多余的后缀","

例如:在人员信息表,根据姓名,年龄,地址,性别等条件查询人员信息。

        使用prefix增加前缀(where),prefixOverrides去除多余前缀(and | or)实现查询功能

	<select id="sqlUse" resultType="com.example.animalhome.web.entity.User">
        select * from user
        <trim prefix="where" prefixOverrides="and | or">
            <if test="name != '' and name != null">
                and name = #{name}
            </if>
            <if test="age > 0 and age == 19">
                and age = #{age}
            </if>
            <if test="sex == '1'.toString()">
                and sex = #{sex}
            </if>
        </trim>
    </select>

例如:根据人员信息表主键id,更新人员姓名、年龄、地址、性别等信息。

        使用prefix增加前缀(set),suffixOverrides去除多余后缀(,),suffix增加后缀(where id = #{id})实现更新用户信息功能

    <update id="updateUser" parameterType="com.example.animalhome.web.entity.User">
        update user
        <trim prefix="set" suffixOverrides="," suffix="where id = #{id}">
            <if test="name != null and name != ''">name= #{name},</if>
            <if test="age != null and age != ''">age= #{age},</if>
            <if test="sex != null and sex != ''">sex= #{sex},</if>
            <if test="address != null and address != ''">address= #{address},</if>
        </trim>
    </update>

例如:人员信息表插入数据。

        使用prefix增加前缀((),suffixOverrides去除多余后缀(,),suffix增加后缀()),实现插入用户信息功能。

<insert id="insertUser" parameterType="com.example.animalhome.web.entity.User">
        INSERT INTO user
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="null != id and '' != id">
                id,
            </if>
            <if test="null != name and '' != name">
                name,
            </if>
            <if test="null != age and '' != age">
                age,
            </if>
            <if test="null != sex and '' != sex">
                sex,
            </if>
            <if test="null != address and '' != address">
                address,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="null != id and '' != id">
                #{id},
            </if>
            <if test="null != name and '' != name">
                #{name},
            </if>
            <if test="null != age and '' != age">
                #{age},
            </if>
            <if test="null != sex and '' != sex">
                #{sex},
            </if>
            <if test="null != address and '' != address">
                #{address},
            </if>
        </trim>
</insert>

四、set标签

        使用set标签可以动态配置SET关键字,和剔除追加到条件末尾的任何不相关的逗号。

例如:根据人员信息表主键id,更新人员姓名、年龄、地址、性别等信息。

<update id="updateUser" parameterType="com.example.animalhome.web.entity.User">
    update user
    <set>
        <if test="name != null and name != ''">name= #{name},</if>
        <if test="age != null and age != ''">age= #{age},</if>
        <if test="sex != null and sex != ''">sex= #{sex},</if>
        <if test="address != null and address != ''">address= #{address},</if>
    </set>
    where id = #{id}
</update>

        通过控制台日志可以发现address后面的逗号被去除!

五、foreach标签

        foreach 标签属性主要有 item,index,open,separator,close,collection。

  1. item:集合中元素迭代时的别名,该参数为必选。
  2. index:在 list 和数组中,index 是元素序号;在 map 中,index 是元素 key。该参数可选。
  3. open:foreach 代码的开始符号,一般是 ”(“,和 close=“)” 合用。常用在 in(),values() 时。该参数可选。
  4. separator:元素之间的分隔符,例如在 in() 的时候,separator=“,” 会自动在元素中间用 “,“ 隔开,避免手动输入逗号导致 SQL 错误,如 in(1, 2,) 这样。该参数可选。
  5. close:foreach 代码的关闭符号,一般是 ”)“,和 open=“(” 合用。常用在 in(),values()时。该参数可选。
  6. collection:要被 foreach 标签循环解析的对象。

        foreach 标签的 collection 属性在接受参数名时,有两种情况:

              匿名参数

                当在 java 方法中没有通过 @Param 注解指定参数名时,列表类型默认参数名为 ”list“,数组类型默认参数名为 ”array“,Map 对象没有默认值。

              具名参数

                java 方法中使用了 @Param 注解指定了参数名称,则 foreach 中的 collection 属性必须为参数名。

例如:根据主键Id集合查询所有符合的人员信息。

dao层:

	//如下两种入参均可用selectAllUser语句
    List<User> selectAllUser(@Param("ids") List<String> ids);
	List<User> selectAllUser(@Param("ids") String[] ids); 

xml:

<select id="selectAllUser" resultType="com.example.animalhome.web.entity.User">
     select * from user where id in
     <foreach collection="ids" item="item" separator="," open="(" close=")">
         #{item}
     </foreach>
</select>

        在使用foreach批量更新、插入数据时,mybatis 会根据XML文件配置,动态生成多条 SQL。而要让 mybatis 成功执行多条语句,须开启允许批量查询设置,即在 jdbc-url 连接信息中添加 &allowMultiQueries=true,否则无法批量执行sql语句!!!如下所示。

例如:批量更新人员信息。

dao层:

int updateAllUser(List<User> users);

xml:

	<update id="updateAllUser">
	    <foreach collection="list" separator=";" item="user">
	        update user
	        <set>
	            <if test="user.name != null and user.name != ''">name= #{user.name},</if>
	            <if test="user.age != null and user.age != ''">age= #{user.age},</if>
	            <if test="user.sex != null and user.sex != ''">sex= #{user.sex},</if>
	            <if test="user.address != null and user.address != ''">address= #{user.address},</if>
	        </set>
	        where id = #{user.id}
	    </foreach>
	</update>

例如:批量插入人员信息。

dao层:

int insertAllUser(List<User> users);

xml:

	<insert id="insertAllUser">
	  INSERT INTO user (id, name, age, address, sex) VALUES
	  <foreach collection="list" separator="," item="user">
	    (#{user.id}, #{user.name}, #{user.age}, #{user.address}, #{user.sex})
	  </foreach>
	</insert>

        上述传参类型都是List、数组类型,如果入参类型是Map,那么foreach又该如何处理呢?

        Map集合在foreach由于没有默认键可用,故需要使用 @Param 注解手动指定一个标识,后面将在foreach中将其作为键使用。该标识任意指定即可,这里使用"maps"

	//dao层方法
	User selectAllUserByMap(@Param("maps") Map<String,Object> maps);

        传入参数为集合时,映射文件的sql标签parameterType属性可省略。由于是Map集合,index、item属性分别表示为该Map集合中的key、value,故可以分别用${k},#{v}来获取该Map集合中的key、value。

    Map<String,Object> maps = new HashMap<>();
  	maps.put("name","萨摩耶");
	maps.put("sex","1");
	User user = animalInformationDao.selectAllUserByMap(maps);

	//xml层方法
	<select id="selectAllUserByMap" resultType="com.example.animalhome.web.entity.User">
        select * from user
        <where>
            <foreach collection="maps" index="k" item="v">
                AND  ${k} = #{v}
            </foreach>
        </where>
    </select>

操作日志如下:

六、choose、when、otherwise标签

        MyBatis 中动态语句 choose-when-otherwise 类似于 Java 中的 switch-case-default 语句。由于 MyBatis 并没有为 if 提供对应的 else 标签,如果想要达到<if>...<else>...</else> </if> 的效果,可以借助 <choose>、<when>、<otherwise> 来实现。

	//dao层
	List<User> selectUserInfo(User user);

    //xml
	<select id="selectUserInfo"
            parameterType="com.example.animalhome.web.entity.User"
            resultType="com.example.animalhome.web.entity.User">
        SELECT * FROM user
        <where>
            <choose>
                <when test="name != '' and name != null">
                    name=#{name}
                </when>
                <when test="age != '' and age != null">
                    age = #{age}
                </when>
                <when test="sex != '' and sex != null">
                    sex = #{sex}
                </when>
                //otherwise条件的值必须不为空,否则sql报错!!!
                <otherwise>
                    address = #{address}
                </otherwise>    
            </choose>
        </where>
    </select>

七、bind标签

        bind标签可以从OGNL(对象图导航语言)表达式中创建一个变量并将其绑定到上下文
Mybatis中使用Mysql的模糊查询字符串拼接(like) 中也涉及到bind的使用。

	//dao层
	List<User> findUser(@Param("name") String name);

    //xml
	<select id="findUser" resultType="com.example.animalhome.web.entity.User">
        SELECT * FROM user
        <where>
            <if test="name != null and name != ''">
                <bind name="name" value="'%'+name+'%'"/>
                    name like #{name}
            </if>
        </where>
    </select>

八、include标签

        include标签引用,可以复用SQL片段,sql标签中id属性对应include标签中的refid属性,通过include标签将sql片段和原sql片段进行拼接成一个完整的sql语句进行执行。

	<sql id="field">
	    id,name,age,address,sex
	</sql>
        
	<sql id="table">
	    user
	</sql>
        
	<select id="selectUser" resultType="com.example.animalhome.web.entity.User">
	    select 
        	<include refid="field"/>
	    from 
        	<include refid="table"/>
	</select>
	
	等同于:
	<select>
	    select id,name,age,address,sex from user
	</select>

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MyBatis是一个流行的ORM框架,通过Mapper文件将Java对象映射到SQL语句。MyBatis的Mapper文件是一个XML文件,它包含了可以执行的SQL语句。动态SQLMyBatis的一个重要的功能,可以根据不同情况,生成不同的SQL语句,从而实现更加灵活的查询。 if标签是MyBatis动态SQL的一种标签,它可以根据条件生成动态的SQL语句。if标签的语法如下: ``` <if test="condition1"> SQL语句 </if> ``` 其中,test属性表示需要判断的条件,可以是一个字符串表达式或者OGNL表达式。SQL语句则是当满足条件时需要执行的SQL语句。如果条件不满足,则不会执行这段SQL语句。 if标签可以包含多个嵌套的if标签,以实现更加复杂的条件判断。同时,还可以使用choose、when、otherwise标签结合if标签,实现更加灵活的条件判断。例如: ``` <select id="queryUsers" resultType="User"> SELECT * FROM users <where> <if test="username != null and username != ''"> AND username LIKE '%${username}%' </if> <if test="gender != null and gender != ''"> AND gender = #{gender} </if> <choose> <when test="orderBy == 'name'"> ORDER BY username </when> <when test="orderBy == 'age'"> ORDER BY age </when> <otherwise> ORDER BY id </otherwise> </choose> </where> </select> ``` 以上例子是一个查询用户的SQL语句,根据不同情况生成不同的SQL语句。其中,if标签根据传入的参数判断是否需要加入username、gender的查询条件,choose标签根据orderBy的值,生成不同的排序条件。 if标签是MyBatis动态SQL的重要功能之一,可以根据条件生成不同的SQL语句,从而实现更加灵活的查询。熟练掌握if标签的使用,可以使MyBatis开发更加高效和灵活。 ### 回答2: Mybatis是一款流行的Java ORM框架,它提供了许多方便的功能,其中之一就是动态SQL。当我们需要根据不同的条件拼接SQL语句时,就可以使用动态SQL来实现。具体来说,if标签是其中一种实现方式,下面将详解其用法。 if标签可以用于where、set、foreach等标签中,用于判断当前条件是否成立,如果成立就拼接相应的SQL语句,否则不进行任何操作。其基本语法如下: <if test="condition"> SQL语句 </if> 其中,test属性用于指定判断条件,可以是简单的表达式或者是复杂的逻辑语句。下面是一些常用的判断条件: 1. 判断参数是否为空 <if test="param != null"> SQL语句 </if> 2. 判断字符串是否为空 <if test="str != ''"> SQL语句 </if> 3. 判断是否相等 <if test="param == 'value'"> SQL语句 </if> 4. 判断是否大于 <if test="param > 10"> SQL语句 </if> 5. 判断是否包含 <if test="str.indexOf('value') != -1"> SQL语句 </if> 除了以上几种基本用法,if标签还可以嵌套使用,用于实现更复杂的判断逻辑。例如: <if test="param1 != null"> SQL语句 <if test="param2 != null"> SQL语句 </if> </if> 上述代码示例中,如果param1不为空,就会拼接第一个SQL语句;如果param2也不为空,则会在第一个SQL语句之后再拼接第二个SQL语句。 总的来说,if标签是Mybatis动态SQL的基础,能够帮助我们实现更加灵活的SQL拼接,提高代码的可读性和可维护性。学习和掌握其使用方法,对于开发高效、高质量的程序是非常有帮助的。 ### 回答3: MyBatis是一款非常优秀的Java持久层框架,提供了丰富的SQL查询方式。在进行SQL查询的时候,经常需要根据具体的条件组合而成不同的SQL语句。这个时候可以使用MyBatis动态SQL特性。在动态SQL中,if标签是常用的一种方式。下面就来详解一下if标签的用法。 if标签的作用:在SQL语句中根据判断条件动态生成SQL语句。相当于Java中的if语句。 if标签的用法:在Mapper.xml文件中,使用if标签包裹需要动态生成的SQL。if标签的属性为test,表示判断条件。属性值可以是任何符合OGNL规则的表达式,常见的有以下几种方式: 1. 如果条件不为空,则生成相应的SQL语句:<![CDATA[需要动态生成的SQL语句]]>。 例如: <select id="findUser" parameterType="User" resultMap="UserMap"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name = #{name} </if> </where> </select> 当调用findUser方法时,如果传入的name不为空,那么就会生成如下的SQL语句: SELECT * FROM user WHERE name = ? 2. 如果条件为true,则生成相应的SQL语句: 例如: <select id="findUsers" resultMap="UserMap"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select> 当调用findUsers方法时,如果传入的name和age分别为"Tom"和20,那么就会生成如下的SQL语句: SELECT * FROM user WHERE name = 'Tom' AND age = 20 3. 如果条件为false,则不在生成相应的SQL语句: 例如: <select id="findUsers" resultMap="UserMap"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select> 当调用findUsers方法时,如果传入的name为"Tom",age为空,那么就会生成如下的SQL语句: SELECT * FROM user WHERE name = 'Tom' if标签的嵌套: if标签可以进行嵌套,从而实现更加灵活的SQL生成方式。 例如: <select id="findUsers" resultMap="UserMap"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name = #{name} </if> <if test="age != null"> <if test="age < 18"> AND age < 18 </if> <if test="age >= 18 and age < 30"> AND age >= 18 AND age < 30 </if> <if test="age >= 30"> AND age >= 30 </if> </if> </where> </select> 当调用findUsers方法时,如果传入的name为空,age为25,那么就会生成如下的SQL语句: SELECT * FROM user WHERE age >= 18 AND age < 30 以上就是if标签的用法详解使用if标签可以让查询条件更加灵活、动态,深受开发者们的喜爱。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值