MyBatis从入门到精通笔记(4)动态SQL

一 简介

MyBatis提供了强大的动态sql功能,使用起来非常方便。在MyBtais3之前的版本,动态SQL较为复杂。现在采用了OGNL,已经非常方便了。

二 if

一般用于where条件中,也可以是update或insert

2.1 where中使用if

接口方法

    /**
     * 在where中使用if
     * @param sysUser
     * @return
     */
    List<SysUser> selectByUser(SysUser sysUser);

映射语句
这时需要添加where 1=1,否则有些场景可能会报错

    <select id="selectByUser" resultType="zyc.mybatis.simple.model.SysUser">
        select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
        from sys_user
        where 1=1
        <if test="@org.apache.commons.lang3.StringUtils@isNotEmpty(userName)">
            and user_name like concat('%', #{userName}, '%')
        </if>
        <if test="userEmail != '' and userEmail != null">
            and user_email = #{userEmail}
        </if>

    </select>

2.2 update更新列中使用if

需求:
只更新有值的字段。一般选择性更新都是以Selective作为后缀

接口方法

    /**
     * 根据主键更新
     * 子啊update时使用if
     *
     * @param sysUser
     * @return
     */
    int updateByIdSelective(SysUser sysUser);

映射语句

    <update id="updateByIdSelective">
        update sys_user
        set
        <if test="userName != null and userName != ''">
            user_name = #{userName},
        </if>
        <if test="userPassword != null and userPassword != ''">
            user_password = #{userPassword},
        </if>
        <if test="userEmail != null and userEmail != ''">
            user_email = #{userEmail},
        </if>
        <if test="userInfo != null and userInfo != ''">
            user_info = #{userInfo},
        </if>
        <if test="headImg != null">
            head_img = #{headImg, jdbcType=BLOB},
        </if>
        <if test="createTime != null">
            create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
        id = #{id}
        where id = #{id}
    </update>

2.3 insert时动态插入

接口方法

    /**
     * 动态插入
     * @param sysUser
     * @return
     */
    int insertSelective(SysUser sysUser);

映射sql

    <insert id="insertSelective" useGeneratedKeys="true" keyProperty="id">
        insert into sys_user(
        user_name, user_password,
        <if test="userEmail != null">
            <if test="userEmail != ''">
                user_email,
            </if>
        </if>
        user_info, head_img, create_time)
        values(
        #{userName}, #{userPassword},
        <if test="userEmail != null">
            <if test="userEmail != ''">
                #{userEmail},
            </if>
        </if>
        #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})
    </insert>

三 choose

该标签能够实现if..else if...else的逻辑。(注意多个when是顺序判断的,只要有一个满足了,后面就不会生效。就是java的if ..else语法)
choose标签需要和when和otherwise两个标签配合使用。一个choose中至少有一个when,有0个或者1个otherwise。

接口方法

    /**
     * 根据用户 id 或用户名查询
     * choose标签
     * @param sysUser
     * @return
     */
    SysUser selectByIdOrUserName(SysUser sysUser);

映射sql
这里的limit 0也是个技巧

    <select id="selectByIdOrUserName" resultType="zyc.mybatis.simple.model.SysUser">
        select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
        from sys_user
        where 1 = 1
        <choose>
            <when test="id != null">
                and id = #{id}
            </when>
            <when test="userName != null and userName != ''">
                and user_name = #{userName}
            </when>
            <otherwise>
                limit 0
            </otherwise>
        </choose>
    </select>

四 where、set、trim

这3个标签功能很像,实际上where和set就是trim的一种用法

4.1 where

前面我们在where中使用if,还需要写 where 1=1,这样太麻烦而且不够优雅。

作用
如果该标签包含的元素中有返回值,就插入一个where ;如果where后面的字符串是以AND 和OR 开头的,就将它们剔除。

我们修改上面的selectByUser映射语句

    <select id="selectByUser" resultType="zyc.mybatis.simple.model.SysUser">
        select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
        from sys_user
        <where>
            <if test="@org.apache.commons.lang3.StringUtils@isNotEmpty(userName)">
                and user_name like concat('%', #{userName}, '%')
            </if>
            <if test="userEmail != '' and userEmail != null">
                and user_email = #{userEmail}
            </if>
        </where>
    </select>

4.2 set用法

用法
如果该标签包含的元素中有返回值,就插入一个set :如果set 后面的字符串是以逗号结尾的,就将这个逗号剔除
修改上面的updateByIdSelective方法

    <update id="updateByIdSelective">
        update sys_user
        <set>
            <if test="userName != null and userName != ''">
                user_name = #{userName},
            </if>
            <if test="userPassword != null and userPassword != ''">
                user_password = #{userPassword},
            </if>
            <if test="userEmail != null and userEmail != ''">
                user_email = #{userEmail},
            </if>
            <if test="userInfo != null and userInfo != ''">
                user_info = #{userInfo},
            </if>
            <if test="headImg != null">
                head_img = #{headImg, jdbcType=BLOB},
            </if>
            <if test="createTime != null">
                create_time = #{createTime, jdbcType=TIMESTAMP},
            </if>
            id = #{id},
        </set>
        where id = #{id}
    </update>

4.3 trim 用法

trim的功能最强大,where、set都可以用trim实现

trim标签的属性

  • prefix :当trim 元素内包含内容时,会给内容增加prefix 指定的前缀。
  • prefixOverrides :当trim 元素内包含内容时,会把内容中匹配的前缀字符串去掉。
  • suffix :当trim 元素内包含内容时,会给内容增加suffix 指定的后缀。
  • suffixOverrides :当trim 元素内包含内容时,会把内容中匹配的后缀字符串去掉。

如,用trim实现where
这里的and和or后的空格也和关键,这样表明是一个独立的单词,不会和order等字段名匹配。实际的prefixOverrides更复杂,还需要处理各种空白字符,这里只是简化!

<trim prefix="where" prefixOverrides="and |or ">
	...
</trim>

五 foreach

我们经常会使用in查询,这时foreach可以方便地实现需求。

foreach 可以对数组、Map 或实现了工terable 接口(如List 、Set )的对象进行遍历。数组在处理时会转换为List 对象,因此foreach 遍历的对象可以分为两大类Iterable类型和Map 类型

5.1 实现in集合

接口方法

    /**
     * 根据用户 id 集合查询
     * foreach用法
     * @param idList
     * @return
     */
    List<SysUser> selectByIdList(List<Long> idList);

映射sql

    <select id="selectByIdList" resultType="zyc.mybatis.simple.model.SysUser">
        select id,
        user_name userName,
        user_password userPassword,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
        from sys_user
        where id in
        <foreach collection="list" open="(" close=")" separator="," item="id" index="i">
            #{id}
        </foreach>
    </select>

5.2 标签属性

  • collection :必填,值为要选代循环的属性名。这个属性值的情况有很多。
  • item:变量名,值为从法代对象中取出的每一个值。
  • index :索引的属性名,在集合数组情况下值为当前索引值,当选代循环的对象是Map类型时,这个值为Map 的key (键值)。
  • open:整个循环内容开头的字符串。
  • close :整个循环内容结尾的字符串。
  • separator :每次循环的分隔符

5.3 collection的属性设置规则

只有一个参数时

  1. 集合用collection,List可以用list(就像上面,这两者都可以
  2. 数组用array
  3. 推荐使用@Param 来指定参数的名字,这时可以设置成我们自定义地名字
  4. 可以使用默认值_parameter

方法有多个参数时
在笔记2中提过,推荐使用@Param来指定名字

5.4 实现批量插入

首先要实现批量插入,对应的数据库必须支持。我们下面会以MySQL为例(MySQL支持这种语法

接口方法

    /**
     * 批量插入用户信息
     *
     * @param userList
     * @return
     */
    int insertList(List<SysUser> userList);

对应sql

    <insert id="insertList" useGeneratedKeys="true" keyProperty="id">
        insert into sys_user(
        user_name, user_password,user_email,
        user_info, head_img, create_time)
        values
        <foreach collection="list" item="user" separator=",">
            (
            #{user.userName}, #{user.userPassword},#{user.userEmail},
            #{user.userInfo}, #{user.headImg, jdbcType=BLOB}, #{user.createTime, jdbcType=TIMESTAMP})
        </foreach>
    </insert>

从MyBatis 3.3. 1版本开始,MyBatis 开始支持批量新增回写主键值的功

这个功能首先要求数据库主键值为自增类型,同时还要求该数据库提供的JDBC 驱动可以支持返回批量插入的主键值(JDBC 提供了接口,但并不是所有数据库都完美实现了该接口,MySQL完美支持)所以应用场景不多,我个人觉得主键最好还是自己设置比较好

用法就是和普通插入一样useGeneratedKeys="true" keyProperty="id"

5.5 动态update

接口方法

    /**
     * 通过 Map 更新列
     *
     * @param map
     * @return
     */
    int updateByMap(Map<String, Object> map);

    int updateByMap2(@Param("m1") Map<String, Object> map);//测试@Param效果

映射语句

	<update id="updateByMap">
		update sys_user 
		set 
		<foreach collection="_parameter" item="val" index="key" separator=",">
			${key} = #{val}
		</foreach>
		where id = #{id}
	</update>
    <update id="updateByMap2">
        update sys_user
        set
        <foreach collection="m1" item="val" index="key" separator=",">
            ${key} = #{val}
        </foreach>
        where id = #{m1.id}
    </update>

六 bind

bind 标签可以使用OGNL 表达式创建一个变量并将其绑定到上下文中

<bind name="userNameLike" value="'%'+userName+'%'"/>

七 多数据支持

具体没试,记录几个重点

  1. 匹配规则:DB VENDOR 的匹配策略为DatabaseMetaData#getDatabaseProductName ()返
    回的字符串包含property 中name 部分的值即可匹配
  2. 很多标签都有databaseId属性。可以指定对应的数据库类型,也可以不指定。
  3. MyBatis 会加载不带databaseId 属性和带有匹配当前数据库databaseld 属性的所有语句。如果同时找到带有databaseId 和不带databaseId的相同语句,则后者会被舍弃
  4. 实现多数据支持。可以写两条sql,也可以使用if标签实现局部更换

八 OGNL用法

在这里插入图片描述

参考

  1. 《MyBatis 从入门到精通》
  2. 源码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值