Dynamic SQL of MyBatis

Posted by sdjensen on Wed, 02 Feb 2022 22:28:27 +0100

catalogue

Build environment

if

choose,when,otherwise

trim,where,set

sql fragment

foreach

Dynamic SQL refers to generating different SQL statements according to different conditions under different circumstances

Build environment

database

CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT 'Blog id',
	`title` VARCHAR(100) NOT NULL COMMENT 'Blog title',
	`author` VARCHAR(30) NOT NULL COMMENT 'Blogger',
	`create_time` DATETIME NOT NULL COMMENT 'Creation time',
	`views` INT(30) NOT NULL COMMENT 'Views'
)ENGINE=INNODB DEFAULT CHARSET=utf8

Entity class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

Entity classes correspond to mapper and xml files

public interface BlogMapper {
}
<?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.zhouyue.dao.BlogMapper">

</mapper>

UUID tool class

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

Insert data test

    @Test
    public void test(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        mapper.addBlog(new Blog(IDUtils.getId(), "MyBatis study", "Su Fuai", new Date(), 154));
        mapper.addBlog(new Blog(IDUtils.getId(), "Spring study", "Su Fuai", new Date(), 632));
        mapper.addBlog(new Blog(IDUtils.getId(), "SpringMVC study", "Su Fuai", new Date(), 148));
        mapper.addBlog(new Blog(IDUtils.getId(), "SpringBoot study", "Su Fuai", new Date(), 248));
        sqlSession.close();
    }

if

Realize the following functions:

If the title is passed in, the specified blog will be queried. If the author is passed in, all blogs of the author will be queried. If nothing is posted, all blogs will be queried

We can use if in MyBatis to realize this function

Tabular data

Interface: receive parameters through map

    //Query blog
    List<Blog> queryBlogIF(Map map);

sql statement: Here we use if to realize the splicing of different sql statements under different circumstances

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

test

@Test
    public void test1(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Map map = new HashMap();
//        map. Put ("title", "spring MVC learning");
//        map.put("author", "Su Fu AI");
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog :
                blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

No parameters

Pass in title

Incoming author

By passing in title and author, we can find that the sql statement splices both

choose,when,otherwise

choose, when and otherwise statements can be understood as switch, case and default statements

Use this statement to realize that if you pass in title, you will query the specified blog; if you pass in author, you will query all blogs of the author; if you pass nothing, you will query the blog with 632 views

sql statement

<select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog where 1=1
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views = 632
            </otherwise>
        </choose>
    </select>

The test statement is the same as before

No parameters

Pass in title

Incoming author

By passing in title and author, we can find that the sql statement only splices the title, that is, the content in the front when tag

Add a blog with the same name. You can find that both blogs have been found

trim,where,set

where

In the previous case, in order to meet the splicing of where, we used the form of 1 = 1, but this is obviously not good, so we can use the where tag for splicing

The WHERE element inserts the "WHERE" clause only if the child element returns anything. Moreover, if clause starts with the "AND" OR ", WHERE element will also remove them.

Use where to modify the above case

sql statement

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

set

The function of SET statement is similar to that of where. A similar solution for dynamically updating statements is called set. The set element can be used to dynamically include columns that need to be updated and ignore other columns that do not need to be updated. The set element will dynamically insert the set keyword at the beginning of the row and delete additional commas (these commas are introduced when assigning values to columns using conditional statements).

Examples

Interface

    //Update blog
    int updateBlog(Map map);

sql statement

<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>

Testing

@Test
    public void test2(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        Map map = new HashMap();
        map.put("title", "SpringMVC");
        map.put("author", "Su Fugo");
        map.put("id", "a37f63f48d384f069f062f5c688114e5");
        int i = mapper.updateBlog(map);
        System.out.println(i);
        sqlSession.close();
    }

trim

We can use trim to realize the functions of where and set

Implement where

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <trim prefix="WHERE" prefixOverrides="AND |OR">
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </trim>
    </select>

Implement set

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

Generally speaking, dynamic sql is still sql statement in essence, but we can execute a logical code at the sql level

sql fragment

Sometimes, we will extract some common parts of sql to facilitate reuse and reduce code redundancy. For example, in the above case, we wrote the following code

We can consider extracting it and using sql tags

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

Then introduce the fragment and use the include tag

Corresponding functions can also be realized

foreach

We have the following information

You need to query the blog information whose author is Su Fuai and blog id is 2 or 3

Using sql statements

select * from blog where author = 'Su Fuai' and (id = 2 or id = 3)

In MyBatis, we can use foreach to implement it

Collection: indicates the name of the incoming collection

item: the name of each element in the collection

open: what do you start with

close: what does it end with

Separator: separator

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

Test:

    @Test
    public void test3(){
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        List<Integer> ids = new ArrayList<>();
        ids.add(2);
        ids.add(3);
        Map map = new HashMap();
        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

It can be found that the sql is successfully spliced and the correct results are obtained

In a word, dynamic sql is actually splicing sql statements

Topics: Java Mybatis Back-end