MyBatis动态sql

动态sql

动态 sql 是Mybatis的强大特性之一,能够完成不同条件下不同的 sql 拼接。

我们可以先思考这样一个问题某系统要完成用户注册功能,会在数据库中要插入一个用户,用户注册时,用户名密码是必填项
其他字段(昵称、性别、生日、头像)是选填项,
比如用户完成注册功能式传递的参数是用户名和密码的必填项,我们这样设计sql:直接插入用户名和密码,

<insert id="insertUser" parameterType="User">
        insert into user(username, password) values (#{username},#{password});
</insert>

这样设计存在一个缺陷,如果用户提交的不仅仅包括必填项,还包括选填项,显然这个sql已经不能满足我们的业务了,我们需要对这个sql进行改进,如果用户传递的参数包括选填项,我们就要使用用户传入的参数,如果用户只传入必填项,选填项为null,我们使用默认值就可以了, 这种sql就被称为动态sql

其实本质就是根据不同的的条件生成不同的sql语句,本质依然是sql语句,只是在sql层面,增加了一些逻辑语句

环境准备

创建一个数据库表blog

drop table if exists 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  COMMENT '创建时间',
    `views` int(30)  COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

数据库实体类编写 使用lombok插件完成getset以及无参有参构造


@Data
@NoArgsConstructor
@AllArgsConstructor

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

springboot 配置文件中配置mybatis

spring.datasource.username=root
spring.datasource.password=tong0726
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#整合mybatis
mybatis.type-aliases-package=com.doer.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

编写mapper接口 以及mapper.xml配置文件


@Mapper
@Repository
public interface BlogMapper {

    //插入博客
    int insertBlog(Blog blog);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">


<mapper namespace="com.doer.mapper.BlogMapper">
    

</mapper>

if 标签

编写BlogMapper接口

@Mapper
@Repository
public interface BlogMapper {

    //插入博客
    int insertBlog(Blog blog);
}

插入博客的字段创建时间如果是选填项,我们可以使用mybatis提供的if标签

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


<mapper namespace="com.doer.mapper.BlogMapper">
    <insert id="insertBlog" parameterType="User">
        insert into mybatis.blog(
        			id, title, author,
                    <if test="createTime != null">
                         #{createTime},
                    </if>
                    views)
            values (
                    #{id},
                    #{title},
                    #{author},
                    <if test="createTime != null">
                        #{createTime},
                    </if>
                    #{views}
                                )
    </insert>

</mapper>

接下进行测试,
选择创建时间的字段


@Autowired
BlogMapper blogMapper;
@Test
void insertUser() {
    Blog blog = new Blog();
    blog.setId("1");
    blog.setAuthor("doer");
    blog.setTitle("一月");
    blog.setCreateTime(new Date());
    blog.setViews(1);
    blogMapper.insertBlog(blog);


}

不选则创建时间字段

@Test
void insertUser1(){
    Blog blog = new Blog();
    blog.setId("1");
    blog.setAuthor("doer");
    blog.setTitle("一月");

    blog.setViews(1);
    blogMapper.insertBlog(blog);
}

在这里插入图片描述

可以看到输出结果中完成了动态sql的插入

在select语句中使用if标签

接口

//查询博客,如果传入的是一个title就查询title对应的博客,如果是什么都不传入,将所有博客查询出来
List<Blog> queryBlogIf(Map map);

编写对应mapper,xml

<select id="queryBlogIf" parameterType="map" resultType="Blog">
    select * from blog where 
    <if test="title != null">
         title = #{title}

    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</select>

测试

@Test
void queryBlogIf(){
    Map map = new HashMap();
    map.put("author","doer");
    List<Blog> blogs = blogMapper.queryBlogIf(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
}

我们在测试中只传入了一个参数author,相当于if标签中的title标签并没有生效,此时如果我们执行会出现sql异常
在这里插入图片描述
发现我们写的sql中多了一个and,此时解决的办法就是引入where标签

where标签

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

对于出现and错误的例子我们使用where标签就可以解决这个问题

<select id="queryBlogIf" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <if test="title != null">
            title = #{title}

        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>

进行测试

@Test
    void queryBlogIf(){
        Map map = new HashMap();
        map.put("author","doer");
        List<Blog> blogs = blogMapper.queryBlogIf(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }

在这里插入图片描述
可以发现mybatis已经将我们sql语句中的and去除

set标签

where元素是将额外的and和or关键字删除
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号

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

测试


 @Test
    void updateBlog(){
        Map map = new HashMap();
        map.put("id",1);
        map.put("title","二月");
        blogMapper.updateBlog(map);
    }

choose (when, otherwise)

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

<select id="queryBlogChoose" resultType="Blog" parameterType="map">
    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>

foreach

对集合进行遍历时可以使用该标签。标签有如下属性:

  • collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每一个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

接口


List<Blog> queryBlogForEach(List<Integer> list);

sql

select * from user where id in(1,2,3)

编写mapper.xml文件

<select id="queryBlogForEach" parameterType="map" resultType="Blog">
    select * from mybatis.blog
        <where>
            <foreach collection="list" item="id" separator="," open="id in (" close=")">
                id = #{id}
            </foreach>
        </where>
</select>

测试

@Test
void queryBlogForEach(){
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    List<Blog> blogs = blogMapper.queryBlogForEach(list);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值