Mybatis之动态SQL语句实现


动态SQL语句实现

if 查询

接口

public interface BlogMapper {

    List<Blog> queryBlogIF(Map map);
}

Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="allen.dao.BlogMapper">

    <!--    根据不同查询条件查询-->
    <!--    where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。-->
    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>
</mapper>

测试

public class MyTest {

    @Test
    public void queryBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,String> map = new HashMap<>();
        //根据 xml 文件查询 author 字段值为"保尔"的 Blog
        map.put("author","保尔");
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }
}

trim(where,set)

where

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <if test="state != null">
         state = #{state}
    </if>
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
  </where>
</select>

如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:

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

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

SET

用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。

与 set 元素等价的自定义 trim 元素

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

注意,我们覆盖了后缀值设置,并且自定义了前缀值。

choose(和when配合使用)

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

接口

public interface BlogMapper {

    List<Blog> queryBlogChoose(Map map);
}

Mapper.xml

<!--    choose-when 相当于java中的 switch-case-->
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
    select * from blog
    <where>
    <choose>
        <when test="title != null">
            and title = #{title}
        </when>
        <when test="author != null">
            and author = #{author}
        </when>
        <otherwise>
            views = #{views}
        </otherwise>
    </choose>
    </where>
</select>

测试

@Test
public void queryBlogChoose(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String,String> map = new HashMap<>();
    //当 title 不为 null 时,只返回 title 为 "java so easy"的 Blog,不再往下执行
    map.put("title","java so easy");
    map.put("views","510");

    List<Blog> blogs = mapper.queryBlogChoose(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }

    sqlSession.close();
}

SQL片段

有的时候,我们可能想要将一些公共的部分抽取出来,方便复用!

1.使用SQL标签抽取公共部分
2.在需要使用的地方使用 include 标签引入即可

Mapper.xml

<!--    提高代码复用-->
<sql id="if-title-author">
    <if test="title != null">
        and title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <!--    包含引用sql语句 -->
        <include refid="if-title-author"></include>
    </where>
</select>

注意事项:
1.最好基于单表定义SQL片段
2.不要在SQL片段中使用where标签

测试

@Test
public void queryBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map<String,String> map = new HashMap<>();
//        map.put("title","java so easy");
    map.put("author","保尔");
    List<Blog> blogs = mapper.queryBlogIF(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }

    sqlSession.close();
}

输出

[allen.dao.BlogMapper.queryBlogIF]-==>  Preparing: select * from blog WHERE author = ? 
[allen.dao.BlogMapper.queryBlogIF]-==> Parameters: 保尔(String)
[allen.dao.BlogMapper.queryBlogIF]-<==      Total: 2
Blog(id=b29f1be4a8d24ccabe26f316d834f052, title=钢铁是怎样炼成的, author=保尔, createTime=Sun Nov 22 22:50:07 CST 2020, views=510)
Blog(id=ba66644c43964e8fa62a0b229bf280df, title=py so easy, author=保尔, createTime=Mon Nov 23 22:06:39 CST 2020, views=20)

foreach

接口

public interface BlogMapper {

    List<Blog> queryBlogForeach(Map map);
}

Mapper.xml

<!--    foreach查询-->
<!--    select * from blog where 1=1 and (id=1 or id=2 or id=3)-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>

测试1 (ids为空)

@Test
    public void queryBlogForeach(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
        ArrayList<Integer> ids = new ArrayList<>();
        map.put("ids",ids);

        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

输出1(注意观察 sql 语句)

[allen.dao.BlogMapper.queryBlogForeach]-==>  Preparing: select * from blog
[allen.dao.BlogMapper.queryBlogForeach]-==> Parameters: 
[allen.dao.BlogMapper.queryBlogForeach]-<==      Total: 3
Blog(id=1, title=钢铁是怎样炼成的, author=保尔, createTime=Sun Nov 22 22:50:07 CST 2020, views=510)
Blog(id=2, title=java so easy, author=保尔1, createTime=Mon Nov 23 22:05:53 CST 2020, views=20)
Blog(id=3, title=py so easy, author=保尔, createTime=Mon Nov 23 22:06:39 CST 2020, views=20)

测试2(ids 传入参数1,2)

@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    map.put("ids",ids);

    List<Blog> blogs = mapper.queryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

输出2(注意观察 sql 语句)

[allen.dao.BlogMapper.queryBlogForeach]-==>  Preparing: select * from blog WHERE ( id=? or id=? ) 
[allen.dao.BlogMapper.queryBlogForeach]-==> Parameters: 1(Integer), 2(Integer)
[allen.dao.BlogMapper.queryBlogForeach]-<==      Total: 2
Blog(id=1, title=钢铁是怎样炼成的, author=保尔, createTime=Sun Nov 22 22:50:07 CST 2020, views=510)
Blog(id=2, title=java so easy, author=保尔1, createTime=Mon Nov 23 22:05:53 CST 2020, views=20)

==动态SQL就是在拼接SQL语句,只要保证SQL的正确性,按照SQL的格式排列即可==

建议:先在 Mysql 中写出对应的 SQL 语句,再对应修改为动态SQL语句即可。


文章作者: Hailong Gao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hailong Gao !
评论
  目录