Mybatis (5) – Dynamic SQL

The dynamic SQL technology of the Mybatis framework is a function of dynamically assembling SQL statements according to specific conditions. The meaning of its existence is to

Solve the pain point problem when splicing SQL statement strings.

Example: Query with multiple query conditions. If the conditions are set, they must appear in sql.
Be careful with setting and specifying default values. null and “” (empty string)

if

EmpMapper.java

 List<Emp> getEmpByCondition(Emp emp);

EmpMapper.xml

 <select id="getEmpByCondition" resultType="Emp">
        select*
        from t_emp
        where
        <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
        <if test="empName != null and empName != '' ">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

Test program TestDynamicSql,java

 @Test
    public void testGetEmpByCondition(){
        SqlSession sqlSession = SqlSessionUtil. getSqlSession();
        EmpMapper empMapper = sqlSession. getMapper(EmpMapper. class);
        Emp emp = new Emp(1, "Zhang San", 20, "Male",1);
        List<Emp> list_emp = empMapper. getEmpByCondition(emp);
        list_emp.forEach(System.out::println);
        sqlSession. close();
    }

where

Here, if the condition empName behind where is set to empty, then it is wrong to use the test class query.

In the same way, if the age and gender are set to be empty, then there will be an empty shell of select * from t_emp where

How to solve?

Method 1: Add the condition of constant establishment

EmpMapper.xml

 <select id="getEmpByCondition" resultType="Emp">
        select*
        from t_emp
        where 1 = 1
        <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
        <if test="empName != null and empName != '' ">
            and emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </select>

Continue to query the situation where the above fields are all empty, and see that the result does not report an error, and the query is correct

Method 2: Use where tag

EmpMapper.xml

 <select id="getEmpByCondition" resultType="Emp">
        select*
        from t_emp
        <where>
            <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                and age = #{age}
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>
    </select>

Continue testing for null values:

Verified the conclusion:

If none of the if conditions in the where tag are met, the where tag has no function, that is, the where keyword will not be added.

assign a value to one of the

test

Verified the conclusion:

If the if condition in the where tag is met, the where tag will automatically add the where keyword, and remove the redundant and at the front of the condition.

Note: the where tag cannot remove the redundant and at the end of the condition

That is, if written as

 <where>
            <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName}
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>
        </where>

At this time, the test will assign a null value to gender, and you will find that the and after the age are still there

trim

trim is used to remove or add content in the label

Common properties:

prefix: Add something in front of the content in the trim tag

prefixOverrides: Remove some content in front of the content in the trim tag

suffix: Add something after the content in the trim tag

suffixOverrides: Remove some content after the content in the trim tag

EmpMapper.xml

 <select id="getEmpByCondition" resultType="Emp">
        select*
        from t_emp
        <!-- There are 4 trim tags
             prefix prefixOverrides suffix suffixOverrides
             prefix adds the specified content in front of the content
             prefixOverrides removes the specified content in front of the content
             suffix adds the specified content after the content
             suffixOverrides removes the specified content after the content
         -->
        <trim prefix="where" suffixOverrides="and">
            <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
            <if test="empName != null and empName != '' ">
                emp_name = #{empName} and
            </if>
            <if test="age != null and age != ''">
                age = #{age} and
            </if>
            <if test="gender != null and gender != ''">
                gender = #{gender} and
            </if>
        </trim>
    </select>

First test is not empty

The and after gender is automatically removed

Then test only the value of age

Then test all empty, and found that because there is no content, so where is not added

choose, when, otherwise

choose, when, otherwise are equivalent to if…, else if…, else

EmpMapper.java

 List<Emp> getEmpByChoose(Emp emp);

EmpMapper.xml

 <select id="getEmpByChoose" resultType="Emp">
        select*
        from t_emp
        <where>
            <choose>
                <!-- test indicates whether the attribute of the entity class in the current label is valid. If it is valid, it will be spliced into sql. If it is invalid, it will not be spliced -->
                <when test="empName != null and empName != ''">
                    emp_name = #{empName}
                </when>
                <when test="age != null and age != ''">
                    age = #{age}
                </when>
                <when test="gender != null and gender != ''">
                    gender = #{gender}
                </when>
                <otherwise>
                    1 = 1
                </otherwise>
            </choose>
        </where>
    </select>

test program

 @Test
    public void testGetEmpByChoose(){
        SqlSession sqlSession = SqlSessionUtil. getSqlSession();
        EmpMapper empMapper = sqlSession. getMapper(EmpMapper. class);
        Emp emp = new Emp(1, "Zhang San", 20, "Male",1);
        List<Emp> list_emp = empMapper. getEmpByChoose(emp);
        list_emp.forEach(System.out::println);
        sqlSession. close();
    }

It is found that choose, when and otherwise will choose the first one that meets the conditions. As long as one meets the conditions, it will not be judged later, and will not be included in the conditions, so each when does not need to add and, only the first condition that is established will be executed

foreach

More important tags are used for batch addition and batch deletion.

Add in batches

EmpMapper.java

 int insertMoreEmp(@Param("emps") List<Emp> emp);

EmpMapper.xml

 <insert id="insertMoreEmp" useGeneratedKeys="true" keyProperty="empId">
        insert into t_emp
        values
        <!--foreach-tag
             collection attribute: Just put it into the variable defined in the Param annotation of the Mapper interface
             item can be understood as a row of data, that is, an object
             separator represents the separator, after each cycle, it is divided by, and the last time there is no
        -->
        <foreach collection="emps" item="emp" separator=",">
            <!-- emp.empName is used here because the return value type is List, and emp is the entity object of each row of data -->
            (null, #{emp.empName}, #{emp.age}, #{emp.gender}, #{emp.deptId})
        </foreach>
    </insert>

test program

 @Test
    public void testInsertMoreEmp(){
        SqlSession sqlSession = SqlSessionUtil. getSqlSession();
        EmpMapper empMapper = sqlSession. getMapper(EmpMapper. class);
        List<Emp> list_emp = new ArrayList<>();
        list_emp.add(new Emp(null,"Saturday",23,"Male",3));
        list_emp.add(new Emp(null,"Zhu Ba",25,"Female",2));
        list_emp.add(new Emp(null,"Li Jiu",22,"Male",1));
        int i = empMapper.insertMoreEmp(list_emp);
        System.out.println("insert:" + i + "line");
        sqlSession. close();
    }

Batch delete

Delete method 1

EmpMapper.java

int deleteMoreEmp(@Param("empIds") Integer[] empIds);

EmpMapper.xml

 <delete id="deleteMoreEmp">
        delete from t_emp where emp_id in (
        <foreach collection="empIds" item="empId" separator=",">
            #{empId}
        </foreach>)
    </delete>

test

 @Test
    public void testDeleteMoreEmp(){
        SqlSession sqlSession = SqlSessionUtil. getSqlSession();
        EmpMapper empMapper = sqlSession. getMapper(EmpMapper. class);
        Integer[] empIdArr = {8,9,10};
        int i = empMapper.deleteMoreEmp(empIdArr);
        System.out.println("Delete:" + i + "line");
        sqlSession. close();
    }

Delete Method 2

EmpMapper.xml

 <!--Method 2-->
    <delete id="deleteMoreEmp">
        delete
        from t_emp
        where emp_id in
        <!-- What does open start and close end with -->
        <foreach collection="empIds" item="empId" separator="," open="(" close=")">
            #{empId}
        </foreach>
    </delete>

Test: Automatically added front and rear brackets

Delete method 3

EmpMapper.xml

 <delete id="deleteMoreEmp">
        delete
        from t_emp
        where
        <foreach collection="empIds" item="empId" separator="or">
            emp_id = #{empId}
        </foreach>
    </delete>

Test: use or to splice conditions

Summary

Attributes of the foreach tag

collection: set the array or collection to be looped

item: Use a string to represent each data in the array or collection

separator: Set the separator between the data of each cycle

open: what to start the loop with

close: what the loop’s everything ends with

SQL fragment

sql fragment, which can record a public sql fragment, and import it through the include tag where it is used

EmpMapper.java

List<Emp> getAllEmp();

EmpMapper.xml

 <sql id="empColumns">
        emp_id, emp_name, age, gender, dept_id
    </sql>
    <select id="getAllEmp" resultType="Emp">
        select
        <!-- When using it, use the include refid attribute to put the id in sql -->
        <include refid="empColumns"></include>
        from t_emp
    </select>

test

 @Test
    public void testGetAllEmp(){
        SqlSession sqlSession = SqlSessionUtil. getSqlSession();
        EmpMapper empMapper = sqlSession. getMapper(EmpMapper. class);
        List<Emp> list_emp = empMapper. getAllEmp();
        list_emp.forEach(System.out::println);
        sqlSession. close();
    }