Mybatis之动态SQL

本篇文章已同步更新至github仓库JavaSummary,欢迎star!

简介

  • 动态sql:根据不同的条件生成不同的SQL语句

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

    • if
    • choose (when, otherwise)
    • trim (where, set)
    • foreach
  • 动态sql本质还是SQL语句,只是可以在SQL层面去执行一个逻辑代码

动态SQL

搭建环境

a. 创建数据表

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

b. 创建实体类

package com.pojo;
import lombok.Data;
import java.util.Date;

@Data
public class Blog {
    private String id;
    private String title;
    private String author;
    // 属性名和字段名不一致,在mybatis-config.xml中设置mapUnderscoreToCamelCase为True
    private Date createTime;        
    private int views;
}

c. 创建Mapper接口和Mapper.xml

package com.dao;

import com.pojo.Blog;

public interface BlogMapper {
    // 插入数据
    int addBlog(Blog blog);
}
<?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="com.dao.BlogMapper">
    <insert id="addBlog" parameterType="com.pojo.Blog">
        insert into mybatis.blog (id, title, author, create_time, views) values
        (#{id}, #{title}, #{author}, #{createTime}, #{views});
    </insert>
</mapper>

d. 在mybatis-config.xml中设置mapUnderscoreToCamelCase为True

设置名描述有效值默认值
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
<settings>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

e. 新增工具类

package com.utils;

import org.junit.Test;
import java.util.UUID;

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

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

f. 编写测试类,向表中添加数据

package com.dao;

import com.pojo.Blog;
import com.utils.IDUtils;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;

public class BlogMapperTest {
    @Test
    public void addBlogTest() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();
        blog.setId(IDUtils.getId());
        blog.setAuthor("one");
        blog.setCreateTime(new Date());
        blog.setViews(999);
        blog.setTitle("first");

        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getId());
        blog.setTitle("second");
        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getId());
        blog.setTitle("third");
        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getId());
        blog.setTitle("forth");
        blogMapper.addBlog(blog);

        sqlSession.commit();

        sqlSession.close();
    }
}

输出:

com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.dao.BlogMapperTest
log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1665404403.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63440df3]
==>  Preparing: insert into mybatis.blog (id, title, author, create_time, views) values (?, ?, ?, ?, ?); 
==> Parameters: 42244ca5eafd42c8ad30c4c2e256417e(String), first(String), one(String), 2021-05-30 20:39:48.37(Timestamp), 999(Integer)
<==    Updates: 1
==>  Preparing: insert into mybatis.blog (id, title, author, create_time, views) values (?, ?, ?, ?, ?); 
==> Parameters: fabffe13e1584f0795b10a82aab478e5(String), second(String), one(String), 2021-05-30 20:39:48.37(Timestamp), 999(Integer)
<==    Updates: 1
==>  Preparing: insert into mybatis.blog (id, title, author, create_time, views) values (?, ?, ?, ?, ?); 
==> Parameters: 07d0169f0fc24a3885dcef91b84d2f45(String), third(String), one(String), 2021-05-30 20:39:48.37(Timestamp), 999(Integer)
<==    Updates: 1
==>  Preparing: insert into mybatis.blog (id, title, author, create_time, views) values (?, ?, ?, ?, ?); 
==> Parameters: 5c41e8a64ff84ff49085e94a2aef6d97(String), forth(String), one(String), 2021-05-30 20:39:48.37(Timestamp), 999(Integer)
<==    Updates: 1
Committing JDBC Connection [com.mysql.jdbc.JDBC4Connection@63440df3]
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@63440df3]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@63440df3]
Returned connection 1665404403 to pool.

Process finished with exit code 0

if

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分

a. Mapper接口

package com.dao;
import com.pojo.Blog;
import java.util.List;
import java.util.Map;

public interface BlogMapper {
    // 查询博客
    List<Blog> queryBlogIF(Map map);
}

b. Mapper.xml

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

c. test

@Test
public void queryBlogIFTest() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    //        map.put("title", "second");
    map.put("author", "one");

    List<Blog> list = blogMapper.queryBlogIF(map);

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

    sqlSession.close();
}

trim (where, set)

where

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

set

  • set 元素可以用于动态包含需要更新的列,忽略其它不更新的列
  • set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateBlogSet" 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>
public interface BlogMapper {
    // 更新博客
    int updateBlogSet(Map map);
}
@Test
public void updateBlogSetTest() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    map.put("title", "java");
    //map.put("author", "one");
    map.put("id", "42244ca5eafd42c8ad30c4c2e256417e");

    int i = blogMapper.updateBlogSet(map);

    sqlSession.commit();

    sqlSession.close();
}

choose (when, otherwise)

  • choose 元素,它有点像 Java 中的 switch 语句
public interface BlogMapper {
    // 更新博客
    int updateBlogChoose(Map map);
}
<select id="queryBlogChoose" parameterType="map" resultType="com.pojo.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>
@Test
public void queryBlogChoose() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();

    map.put("title", "java");
    //map.put("author", "one");
    map.put("views", 999);

    blogMapper.queryBlogChoose(map);

    sqlSession.close();
}

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xylitolz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值