MyBatis08-(动态SQL)

介绍

官方文档

MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意 去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语 句中的强大的动态 SQL 语言得以改进这种情形。

动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有 很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。 MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

什么是动态SQL

动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。

那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise,trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发的效率。

搭建环境

新建一个数据库表:blog

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

创建一个基础工程
1.导包
2.编写配置文件
3.编写实体类
Blog

package com.codeyancy.pojo;

import lombok.Data;

import java.util.Date;

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

}

4.编写实体类对应Mapper接口和Mapper.xml文件
BlogMapper

package com.codeyancy.dao;

import com.codeyancy.pojo.Blog;

import java.util.List;
import java.util.Map;

public interface BlogMapper {

}

BlogMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--configuration核心配置文件-->
<mapper namespace="com.codeyancy.dao.BlogMapper">
    
</mapper>

5.mybatis-config.xml修改

  • 添加开启自动驼峰命名规则(camel case)映射
  • 绑定mapper
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>

    <!--引入外部配置文件-->
    <properties resource="db.properties" >
        <property name="username" value="root"/>
        <property name="pwd" value="123456"/>
    </properties>

    <settings>
        <!--标准的日志工厂实现-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--是否开启自动驼峰命名规则(camel case)映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

    <!--可以给实体类起别名-->
    <typeAliases>
        <package name="com.codeyancy.pojo" />
    </typeAliases>

    <environments default="development">

        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${pwd}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/codeyancy/dao/BlogMapper.xml "/>
    </mappers>

</configuration>

6.编写IdUtils工具类(用于获取随机UUID)

package com.codeyancy.utils;

import org.junit.Test;

import java.util.UUID;

@SuppressWarnings("all")
public class IdUtils {

    public static String getId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    public void test(){
        System.out.println(IdUtils.getId());
        System.out.println(IdUtils.getId());
        System.out.println(IdUtils.getId());
    }

}

获取随机UUID测试结果如图
在这里插入图片描述

插入初始数据

1.编写接口(BlogMapper)

    //插入数据
    int addBlog(Blog blog);

2.编写配置文件(BlogMapper.xml)

    <insert id="addBlog" parameterType="blog">
        insert into mybatis.blog (id,title,author,create_time,views)
        values (#{id},#{title},#{author},#{createTime},#{views})
    </insert>

3.编写测试类添加数据(MyTest)

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

        Blog blog = new Blog();
        blog.setId(IdUtils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("李老师");
        blog.setCreateTime(new Date());
        blog.setViews(9999);

        mapper.addBlog(blog);

        blog.setId(IdUtils.getId());
        blog.setTitle("Java如此简单");
        mapper.addBlog(blog);

        blog.setId(IdUtils.getId());
        blog.setTitle("Spring如此简单");
        mapper.addBlog(blog);

        blog.setId(IdUtils.getId());
        blog.setTitle("SpringMVC如此简单");
        mapper.addBlog(blog);

        session.close();
    }

数据添加成功后数据库结果如图
在这里插入图片描述

项目结构如图所示:
在这里插入图片描述
环境搭建成功!!

if

需求:根据作者名字和博客名字来查询博客!如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询

  1. 编写接口类(BlogMapper)
//查询博客
    List<Blog> queryBlogIF(Map map);
  1. 编写SQL语句(BlogMapper.xml)
 <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>

    </select>

以上sql语句中where 1=1,是不规范的!

这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的SQL 语句,如何解决呢?请看下面的 where 语句!

where的使用

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
通俗的说:这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。

  1. 测试
    @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();

        //map.put("title","SpringMVC如此简单");
        map.put("author","李老师");
        List<Blog> blogs = mapper.queryBlogIF(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

Choose

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

  1. 编写接口类(BlogMapper)
List<Blog> queryBlogChoose(Map map);
  1. 编写SQL语句(BlogMapper.xml)
    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>
  1. 测试
    @Test
    public void queryBlogChoose(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();

        map.put("title","SpringMVC如此简单");
        map.put("author","李老师");
        map.put("views",9999);
        List<Blog> blogs = mapper.queryBlogChoose(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

set

上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?

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

1.编写接口类(BlogMapper)

//更新博客
    int updateBlog(Map map);
  1. 编写SQL语句(BlogMapper.xml)
    <update id="updateBlog" parameterType="map" >
        update mybatis.blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>

3.测试

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

        HashMap map = new HashMap();

        map.put("title","SpringMVC如此简单2");
        map.put("author","李老师");
        map.put("id","bd8881954be24b5c9a277184bbf5a3cc");
        mapper.updateBlog(map);


        sqlSession.close();
    }

SQL片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

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

    <sql id="if-title-author">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{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片段
  • 不要存在where标签

foreach

foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。

将数据库中前三个数据的id修改为1,2,3;
在这里插入图片描述

需求:查询 blog 表中 id 分别为1,2,3的博客信息

1.编写接口类(BlogMapper)

//查询第1-2-3号的记录博客
    List<Blog> queryBlogForeach(Map map);

2.编写SQL语句(BlogMapper.xml)

    <!--
    select * from mybatis.blog where 1=1 and (id=1 or id=2 or id=3)
    我们现在传递一个万能的map,这map中可以存在一个集合!
    -->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog

        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

3.测试

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

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

        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

小结
其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值