12.动态SQL

12.动态SQL

什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句

利用动态SQL这一特性可以彻底摆脱这种痛苦

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

12.1搭建环境

CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT '博客id',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
	`create_time` datetime NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT '浏览量'
) ENGINE=INNODB DEFAULT CHARSET=utf8

创建一个基础工程

  • 导包
  • 编写核心配置文件
  • 编写实体类

注意:java中创建实体类中的时间属性需选择.util,选择.sql不生效

 

@Data
public class Blog {
    private int id;
    private String title;
    private String author;
    private Date createTime;//属性名和字段名不一致
    private int views;
}

如何解决属性名和字段名不一致:

在核心配置文件的Setting方法里加入如下代码:

<settings>
        <!--开启驼峰命名转换-->
        <setting name="mapUnderscoreToCamelCase" value="true "/>
    </settings>
  • 编写工厂类(utils—sqlSessionFactory)
  • 编写实体类对应的Mapper接口和Mapper.xml文件

IF标签

BlogMapper

//查询博客
    List<Blog> queryBlogIF(Map map);

BlogMapper.xml

<mapper namespace="com.itxiaofei.dao.BlogMapper">
    <insert id="addBlog" parameterType="blog">
        insert into mybatis.blog (id, title, author, create_time, views)
        values(#{id},#{title}, #{author}, #{createTime}, #{views});
    </insert>
		<!--if标签是固定的格式-->
    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from mybatis.blog <!--where 1=1-->
	<!--不使用where也可以在后面加where1=1,但是不正规-->
			<where>
        <if test="title != null">
            and title like #{title}
        </if>
        <if test="author != null">
            and author like #{author}
        </if>
			</where>
    </select>
</mapper>

使用where标签的原因:(where 1=1不正规!)

测试:

//测试动态SQL中if
    @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        /*map.put("title","Java并不难");*/
        map.put("author","if小飞");
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

choose (when, otherwise)标签

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

还是上面的例子,但是策略变为:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。

1.BlogMapper

List<Blog> queryBlogChoose(Map map)

2.BlogMapper.xml

<select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    and title like #{title}
                </when>
                <when test="author != null">
                    and author like #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>

3.测试

//测试动态SQL中choose (when, otherwise)标签
    @Test
    public void queryBlogChoose(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        map.put("views","9999");
        /*map.put("title","Java并不难");*/
        /*map.put("author","if小飞");*/
        List<Blog> blogs = mapper.queryBlogChoose(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

trim、where、set标签

where标签:(自动去除“AND” 或 “OR”)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    and title like #{title}
                </when>
                <when test="author != null">
                    and author like #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>

set标签:(自动去除逗号)

<update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>

set测试:

//测试动态SQL中的set标签
    @Test
    public void updateBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        //id后面的参数那么一长串是因为之前加了UUID防止数据太多导致重复
        map.put("id","f125088b7dd74826a6b4eddc42132ad4");
        map.put("title","Python并不难");
        map.put("author","it小飞呀");
        mapper.updateBlog(map);
        sqlSession.close();
    }

trim标签:

trim标签你可以理解为是set和where标签的整合

<!--prefix:前缀 ,prefixOverrides:前缀覆盖内容
            suffix:后缀 ,suffixOverrides:后缀覆盖内容
 -->
  <trim prefix="" prefixOverrides="" suffix="" suffixOverrides="">
            <!--写拼接的sql语句-->
  </trim>

所谓的动态SQL,本质还是SQL,只是我们可以在SQL层面,去执行一个逻辑代码

Foreach(遍历)

 

 

1.编写接口

List<Blog> queryBlogForeach(Map map);

2.Foreach标签的使用

<!--Foreach标签
    select * from blog where and(id=1 or id=2 or id=3)
    下面Foreach标签的作用就是拼接这段话
    我们传递一个万能的map,这个map中可以存在一个集合
    -->
    <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>

3.测试

//测试动态SQL中的Foreach标签
    @Test
    public void queryBlogForeach(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap map = new HashMap();
        //我们不知道到底有多少个数据元素的时候,就可使用ArrayList;<>里面放的是:泛型
        //<>作用就是确定到底存放什么类型
        // 如果知道数据集合有多少个元素,就用数组。
        ArrayList<Integer> ids = new ArrayList<Integer>();
        //Java Map.put()方法:获取Map集合的所有键名
        map.put("ids",ids);
        ids.add(1);
        ids.add(2);
        ids.add(3);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

SQL片段

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

1.使用sql标签抽取公共的部分

<sql id="if-title-author">
        <if test="title != null">
            and title like #{title}
        </if>
        <if test="author != null">
            and author like #{author}
        </if>
    </sql>

2.在需要使用的地方使用Include标签引用即可

<select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <include refid="if-title-author"></include>
        </where>
    </select>

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 先在Mysql中写出完整的SQL,再对应去修改成为我们的动态SQL实现通用即可
posted @ 2022-10-29 17:01  It小飞呀  阅读(276)  评论(0编辑  收藏  举报