动态SQL

作者: JaJa大宝剑 | 来源:发表于2018-05-10 10:27 被阅读0次

在mybatis3之前,需要学习和了解非常多标签,现在采用OGNL表达式语言,消除了许多其他标签
剩下
if
choose
trim
foreach
bind

if用法:

if通常用于WHERE语句中,判断参数是否使用某个查询条件,UPDATE语句中判断是否更新某个字段,INSERT语句中判断是否插入某个字段。

在WHERE语句中使用if

需求:
实现一个用户管理高级查询功能,根据输入的条件去检索用户信息。当只输入用户时,需要根据用户名进行模糊查询,当只输入邮箱时,根据邮箱进行完全匹配;当同时输入用户名和邮箱时,用这两个条件去匹配用户。

<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
    SELECT id,
        user_name userName,
        user_password userPassward,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
    FROM sys_user
    WHERE 1=1
    <if test="userName != null and userEmail != ''">
        AND user_name LIKE concat('%', #{userName}, '%')
    </if>
    <if test="userEmail != null and userEmail != ''">
        AND user_email = #{userEmail}
    </if>
</select>

if标签有一个必填的属性 test, test的属性是一个符合OGNL要求的判断表达式,表达式的结果为TRUE或FALSE,除此之外非0都为true,0为false。

@Test
    public void testSelectByUser() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser sysUser = new SysUser();
            sysUser.setUserName("ad");
            List<SysUser> sysUserList = userMapper.selectByUser(sysUser);

            Assert.assertTrue(sysUserList.size()>0);

//            根据邮箱查
            sysUser.setUserEmail("test@mybatis.tk");
            sysUser.setUserName(null);
            sysUserList = userMapper.selectByUser(sysUser);


//            根据用户和邮箱查
            sysUser.setUserName("ad");
            Assert.assertTrue(sysUserList.size()==0);

        } finally {
            sqlSession.close();
        }
    }

if 用法,加一个<if test ="property != ' ' and property == null">标签
中间加 and 条件。
if中符合条件才会有and条件。

在update中使用if

需求:
只更新变化的字段。需要注意,更新的时候不能将原来有值但没发生变化的字段更新为空或者NULL。
通过IF就可以实现这种动态更新

示例:

   <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>

测试:

    @Test
    public void testUpdateByIdSelective() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setUserName("cccc");


            userMapper.updateByIdSelective(sysUser);

        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
在insert中使用if

应用场景:
在数据表中插入参数是,如果参数值不为空,就传入,如果传入值为空,就使用数据库中默认的值,而不使用空值。

示例:

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

choose用法
可以实现if ...else...的逻辑

案例需求:
当参数id有值的时候,优先使用id查询,当id没有值的时候,便去判断用户名是否有值,如果有值就用用户名查询,如果没有值,就使SQL查询无结果。

方案:

 <select id="selectByIdOrUserName" resultType="pers.congcong.myBatis2.pojos.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>
                and 1 = 2
            </otherwise>
        </choose>
    </select>

测试代码:

@Test
    public void testselectByIdOrUserName() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setId(null);

            SysUser sysUser1 = userMapper.selectByIdOrUserName(sysUser);

            sysUser.setUserName(null);
            sysUser1 = userMapper.selectByIdOrUserName(sysUser);
        } finally {
            sqlSession.close();
        }
    }

where/set/trim用法:

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

where会自动剔除 and 或 or 开头的 and 和 or

<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
        SELECT id,
            user_name userName,
            user_password userPassward,
            user_email userEmail,
            user_info userInfo,
            head_img headImg,
            create_time createTime
        FROM sys_user
        <where>
        <if test="userName != null and userEmail != ''">
            AND user_name LIKE concat('%', #{userName}, '%')
        </if>
        <if test="userEmail != null and userEmail != ''">
            AND user_email = #{userEmail}
        </if>
        </where>
  </select>
set的用法:

如果标签包含元素中的返回值,就插入一个set,如果set后面中的元素是以逗号结尾的,就将这个逗号剔除。
但是如果set元素中没有内容,照样会出现SQL错误,所以,类似id = #{id}这样必然存在的赋值任然需要保留。

例子:

<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>
trim用法:

where和set都是通过trim实现,并且底层都是通过TrimSqlNode实现的。

<trim prefix = "SET" suffixOverrides = ",">
...
</trim>

<trim prefix = "WHERE" prefixOverrides = "AND | OR">
...
</trim>

foreach用法

SQL语句中有时会使用IN关键字,例如 id in (1, 2, 3),可以使用$(ids)方式直接获取值,但是不能放置SQL注入,避免SQL注入就需要使用#{}的方式,这是就要配合使用foreach标签来满足需求。

foreach可以对数组、Map或实现Iterable接口的对象进行遍历

foreach实现in集合

案例需求:
根据用户ID集合查询出所有符合条件的用户

实现:

 <select id="selectByIdList" resultType="pers.congcong.myBatis2.pojos.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>

foreach包含以下属性:
collection:必填,值为要迭代循环的属性名。这个属性值的情况很多。
item:变量名,值为从迭代对象中取出的每一个值。
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是Map类型是,这个值为KEY。
open、close、separator。

foreach实现批量插入:
如果数据库支持批量插入,就可以通过foreach来实现。批量插入是SQL-92新增的特性,目前支持的数据库有DB2、SQL Server8.2及其以上版本、Mysql、Sqlite3.7.11以上、H2。
 批量插入语法如下:

INSERT INTO tablename (colum-a, [colum-b, ....])
VALUES('value-1a', ['value-1b', ...]),
('value-2a', ['value-2b', ...]),
....

例子:

    <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= DATE}
           )
       </foreach>
    </insert>

测试代码:

 @Test
    public void testInsertList() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            List<SysUser> sysUserList = new ArrayList<SysUser>();

            for (int i = 0; i < 2; i++) {
                SysUser sysUser = new SysUser();
                sysUser.setUserName("cc");
                sysUser.setUserPassword("111111");
                sysUser.setUserEmail("testck@qq.com");
                sysUserList.add(sysUser);
            }

            int result = userMapper.insertList(sysUserList);

            for (SysUser s :
                    sysUserList) {
                System.out.println(s.getId());
            }

            Assert.assertEquals(2, result);
        } finally {
            //为了不影响其他测试,这里选择回滚
            sqlSession.rollback();
            sqlSession.close();
        }
    }

这里使用了useGeneratedKeys 和 keyProperty 两个属性,可以实现批量插入后返回主键。

foreach实现动态update
这个主要介绍参数是Map时,foreach怎么实现动态update。

bind标签,创建一个变量并将其绑定到上下文中。

相关文章

  • MyBatis学习:动态sql

    1.动态sql 动态sql是mybatis中的一个核心,什么是动态sql?动态sql即对sql语句进行灵活操作,通...

  • 第十三章 使用动态SQL(一)

    第十三章 使用动态SQL(一) 动态SQL简介 动态SQL是指在运行时准备并执行的SQL语句。在动态SQL中,准备...

  • 第八章 动态SQL

    动态SQL中的元素介绍 动态SQL有什么作用 MyBatis提供了对SQL语句动态组装的功能 动态SQL中的元素 ...

  • 关于Mybatis的一些问题讨论

    Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理 动态sql的用途 Mybat...

  • MyBatis5-动态 SQL

    动态 SQL 什么是动态 SQL 就是动态的对 SQL 进行组装 拼接. : 可以自动去...

  • geoserver动态颜色参数样式、动态sql配置实现

    geoserver动态颜色参数样式、动态sql配置实现 动态颜色参数样式、动态sql 访问方式: http://l...

  • 强大的动态SQL

    1 动态SQL# 那么,问题来了: 什么是动态SQL? 动态SQL有什么作用? 传统的使用JDBC的方法,相信大家...

  • MyBatis:动态 SQL

    1. 动态 SQL 简而言之,动态 SQL 就是在 Mapper 中使用分支、循环等逻辑。常见的动态 SQL 元素...

  • 无标题文章

    ### 一、简答题 #### 1、Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行...

  • 五,MyBatis动态SQL

    一,含义:动态SQL是指根据参数数据动态组织SQL的技术 二,动态SQL的应用场景:比如淘宝搜索的时候,可以动态的...

网友评论

      本文标题:动态SQL

      本文链接:https://www.haomeiwen.com/subject/jweirftx.html