Detailed Interpretation of the MyBatis Persistence Layer Framework: Practical Training for Adding, Deleting, Modifying, and Checking Configuration Files

1 Introduction

Previously, we learned the native development method of the MyBatis persistence layer framework and the Mapper agent development method, which solved the problems of hard coding and cumbersome operations when using JDBC basic code to operate the database. Now that the feedback brought by the article is not bad, let's use the content learned earlier to do a practical case training today.

Looking back, why do we use MyBatis to develop? It is not difficult to understand that MyBatis, as an excellent persistence layer framework, supports custom sql, stored procedures, and advanced mapping. It almost eliminates all JBDC codes and the work of setting parameters and obtaining result sets. It solves the problem of hard coding and cumbersome operation of Java code when using JBDC basic code to operate the database, as shown in the figure:

The training goal of the case in this section: to be able to use the configuration file to realize the operation of adding, deleting, modifying and checking.

2. Preparations

Today we use MyBatis to complete the addition, deletion, modification and query of data in the database. The specific implementation is as follows:

  • Query data
    • query all data
    • Query data details
    • conditional query
  • adding data
  • change the data
    • Modify all fields
    • Modify dynamic fields
  • delete data
    • Deletion of individual data
    • Bulk data deletion

Today's case is given a student data table, including student id, name, gender, grades and other field information, through MyBatis to add, delete, modify and query the data in the database. Due to the length of the article, this series of articles is divided into two articles. The first article explains the query operation, and the latter article is about additions, deletions and changes. If you are interested in this part of the content, please move to the next article.

First of all, we need to create a database table and add data. The SQL statements involved are as follows:

drop table if exists student;

create table student(
	id int primary key auto_increment,
	name varchar(10),
	gender char(1),
	score_english int,
	score_math int
);

insert into student(name,gender,score_english,score_math) values
('张三','男',61,65),
('李四','女',45,38),
('王五','男',85,53),
('小王','男',56,58),
('小樊','女',85,92);

The data table is as follows:

image-20230129193400530

Next, create the entity class Student under the org.chengzi.pojopackage :

public class Student{
    
    
    //id 主键
    private int id;
    //学生姓名
    private String name;
    //学生性别
    private String gender;
    //学生英语成绩
    private int scoreEnglish;
    //学生数学成绩
    private int scoreMath;
    
    //这里省略了Getter and Setter方法和重写的Object中的toString方法
}

Next, write the test case, write the unit test code in Test here, and create the MyBatisTest class in the test code Java file directory. As shown in the picture:

image-20230129194459753

In order to improve the development efficiency of MyBatis, we install the MyBatisX plug-in. This plug-in has two main functions. The first is the mutual jump between the XML mapping configuration file and the Mapper interface, and the second is to automatically generate a statement according to the Mapper interface method, as shown in the figure:

image-20230129194834069

Search for the MyBatisX plugin in File/setting/plugins to download and install it.

The blue picture represents the Mapper interface file, and the red icon represents the sql mapping configuration file. Using this plug-in, you can define methods in the Mapper interface, automatically generate statements in the configuration file, and quickly jump to the corresponding Mapper interface in the configuration file. I think this plug-in is very efficient in the development of MyBatis, and I have been using it since I learned MyBatis.

3. Query all data

In the client page, we usually need to display all the data information. At this time, the underlying code is to use Java to operate the database, query all the information and send it to the client page.

We can query all information through the following steps:

  • Write the Mapper interface
    • Parameters: none
    • result:List<Student>
  • Write sql mapping configuration file
  • Write and execute test code

When analyzing the methods in the Mapper interface, it is mainly to analyze whether parameters and return value types are required according to the requirements of operating data.

3.1 Writing interface methods

Create a StudentMapper interface in the org.chengzi.mapperpackage , and define a method to query all student data in this interface:

public interface StudentMapper {
    
    
    /*
    需求:查询所有学生信息
     */
    List<Student> selectAll();

}

3.2 Write sql statement

Create a directory structure under the resources path org/chengzi/mapper, and the path separator must be used /to ensure that the Mapper interface and the corresponding sql mapping configuration file are in the same file directory. Create the StudentMapper.xml configuration file in this directory.

After writing the corresponding method in the StudentMapper interface, through the icon of the MyBatisX plug-in, we can quickly jump to the corresponding sql mapping configuration file, and the statement is automatically generated. Write a sql statement to query all student information in the sql mapping configuration file:

<?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="org.chengzi.mapper.StudentMapper">
    <select id="selectAll" resultType="student">
        select *
        from student;
    </select>
</mapper>

3.3 Writing test methods

In the MyBatisTest class, write the code for testing and querying all student information, as follows:

public class MyBatisTest {
    
    
    @Test
    public void testSelectAll() throws IOException {
    
    
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        List<Student> students = studentMapper.selectAll();
        System.out.println(students);

        //5. 释放资源
        sqlSession.close();
    }
}

After learning the SSM framework in the future, this part of the code will become very simple. The focus here is on the one line of code that executes the method.

operation result:

image-20230129202650613

It is found here that the information of some fields in the database is not encapsulated into the Java object. The reason for the problem is very simple, because the column names of the tables in the database are inconsistent with the attribute names of the entity classes in the Java code. For example, students’ math scores, in MySQL The method named score_math is used in Java, but it is named scoreMath in Java, and there is no problem with the two naming methods.

There are two ways to solve this problem :

  1. Aliasing data table field names
  2. Use resultMap to define the mapping relationship between field names and attribute names

For example:

<mapper namespace="org.chengzi.mapper.StudentMapper">
    <select id="selectAll" resultType="student">
        select id,name,gender,score_english as scoreEnglish,score_Math as scoreMath
        from student;
    </select>
</mapper>

At this point, the problem that data cannot be encapsulated into objects has been solved, but when querying all student information, we need to list all field names, which is obviously inefficient and not advisable. MyBatis provides sql fragments to solve this problem.

For example:

<mapper namespace="org.chengzi.mapper.StudentMapper">
    <!--
	sql片段
	-->
    <sql id="student_column">
        select id,name,gender,score_english as scoreEnglish,score_Math as scoreMath
    </sql>
    
    <select id="selectAll" resultType="student">
        <include refid="student_column"/>
        from student;
    </select>
</mapper>

The id is used as the unique identifier of the sql fragment, and it is enough to use the <include>label reference in the original sql statement when using it.

This is another problem. If you operate on some fields in the data table, then there will be a large number of sql fragments, which is obviously not advisable. All MyBatis uses the resultMap method to solve this problem.

3.4 Use of resultMap

When solving the problem that some fields in the data table cannot be encapsulated into Java objects, the method of using aliases is inefficient, and the method of sql fragments is not flexible. MyBatis provides the resultMap method to define the mapping relationship between field names and attribute names.

When using, you only need to use the following method to define in the sql mapping configuration file:

<mapper namespace="org.chengzi.mapper.StudentMapper">

    <resultMap id="studentResultMap" type="student">
        <result column="score_english" property="scoreEnglish"/>
        <result column="score_math" property="scoreMath"/>
    </resultMap>
    
    <select id="selectAll" resultMap="studentResultMap">
     select *
        from student;
    </select>
</mapper>

When using this method, it is only necessary to map the part of the field name in the data table that is different from the attribute in the Java entity class, which greatly improves the efficiency. The id in the resultMap tag is used as a unique identifier and used in the statement.

In resultMap, there are two tags available, for mapping to general data, and for mapping to primary key data.

Run the program:

image-20230129210333422

The data in the data table has all been encapsulated into Java objects.

4. Inquiry details

In the client, the data is often not displayed in full, but in part, and the other part usually needs to be viewed in the way of viewing details. At this time, when the user selects the specified student and checks the information, the student's id is sent to the Java code, and all the information of the student is queried through the user id.

We can implement the query details function through the following steps:

  • Write the Mapper interface:
    • Parameter: id
    • Return value: Student
  • Write sql mapping file
  • Execute the test method

When querying details, it is often necessary to pass in a parameter, such as id, to query all the information of the student according to the id, and the returned result is only one record data, so it only needs to be encapsulated into an object.

4.1 Writing interface methods

Define the method of data query based on id in the StudentMapper interface:

/**
  * 查看详情:根据Id查询
  */
Student selectById(int id);

4.2 Write sql statement

Through the quick jump function of MyBatisX, jump to the corresponding sql mapping configuration file. At this time, the statement has been automatically generated, and the previously defined resultMap can be directly used.

<select id="selectById"  resultMap="studentResultMap">
    select *
    from student where id = #{id};
</select>

The above is #{id}a parameter placeholder, similar to the one used before , which will be explained later.

4.3 Writing test methods

In the MyBatisTest class, write the code for testing and querying all student information, as follows:

@Test
    public void testSelectById() throws IOException {
    
    
        //接收参数
        int id =2;
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        Student students = studentMapper.selectById(id);
        System.out.println(students);

        //5. 释放资源
        sqlSession.close();
    }

At this point, unlike the previous query of all student information, the parameters and return values ​​of this method are different. We only need to pass in the parameters received by the Java code, and then we can encapsulate the queried data into a Student class object.

operation result:

image-20230129212902381

4.4 Parameter placeholders

As mentioned earlier, the sql statement is used #{xx}as a parameter placeholder, and you can see from the running log that in fact, Java automatically replaces the parameter placeholder position with during the running process , which solves the sql injection caused by spelling sql strings question. As shown in the picture:

image-20230129213409241

In fact, the placeholder in MyBatis can #{xx}also ${xx}, which is easy to cause sql injection problems when spelling strings, so it is generally used after the from of the sql statement when the table name of the query is uncertain.

It is not difficult to find that the difference between the two is that #{xx}the bottom layer of the placeholder is preparedStatement, while ${xx}the is statement, which has the problem of sql injection. Therefore, it is recommended to use the former as a parameter placeholder in MyBatis development.

4.5 parameterType usage

If there are parameters in the method in the Mapper interface, parameterType should be configured in the corresponding sql mapping file to specify the data type of the parameter, but this attribute can be omitted. It is not difficult to understand that the reason why it can be omitted is because the data type of this parameter has been defined in the Mapper interface file.

as follows:

<mapper>   
	<select id="selectById" parameterType="int" resultMap="studentResultMap">
select * from student where id=#{id};
    </select>
</mapper>

4.6 Handling of special characters

When MyBatis writes sql in the corresponding sql mapping configuration file, some special characters will appear. For example, when the less than sign is used, it will be confused with the <part of . As shown in the picture:

image-20230129233235106

MyBatis also provides a corresponding method to solve this problem, you can use these two methods:

  1. Escape character: used when there are few special characters
  2. CDATE: Use when there are a lot of confusing special characters

For example using escape characters:

image-20230129234459723

Or use the CDATA method:

image-20230129234642325

When using an IDE with the code auto-completion function, only a part of the input is required for auto-completion. This method is used when there are many special characters.

5. Multi-condition query

In the actual operation of the client, we often query data based on the simultaneous satisfaction of multiple conditions, such as querying the information of all students whose English scores and math scores are both greater than 60 in the query case.

The focus here is how to write sql statements.

We can implement the query details function through the following steps:

  • Write the Mapper interface
    • Parameters: all query conditions
    • result:List<Student>
  • Write sql mapping configuration file
  • Execute the test method

5.1 Writing interface methods

To define the method of multi-condition query in the StudentMapper interface, parameters must also be defined when defining the interface. MyBatis has multiple implementation methods for multiple parameters of multi-condition query.

Method one :

Use to @Param("参数名称")mark each parameter, which needs to be used in the mapping configuration file as #{参数名称}a placeholder

List<Student> selectByCondition(@Param("scoreEnglish") int scoreEnglish, @Param("scoreMath") int scoreMath);

Method two :

Encapsulate multiple parameters into an entity object, and use the entity object as the method parameter of the interface. This method requires that #{内容}when , the content inside must be consistent with the attribute name of the entity class.

List<Student> selectByCondition(Student student);

Method three :

Encapsulate multiple parameters into the map collection, and use the map collection as the method parameter of the interface. This method requires that #{内容}when , the content inside must be consistent with the name of the key in the map collection.

List<Student> selectByCondition(Map map);

5.2 Write sql statement

Write the corresponding statement in the StudentMapper.xml file, where resultMap is also used. Example:

<mapper> 
	<select id="selectByCondition" resultMap="studentResultMap">
        select * from student 
                 where score_english > #{scoreEnglish} and score_math > #{scoreMath};
    </select>
</mapper>

5.3 Writing test methods

In multi-condition query, because there are three different methods of setting parameters when defining the Mapper interface, the specific execution methods here are also divided into three different methods.

    @Test
    public void testSelectByCondition() throws IOException {
    
    
        //接收参数
        int scoreEnglish=60;
        int scoreMath=60;
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //4. 执行方法
        //方法1.使用第一种方法定义参数时使用
        List<Student> students = studentMapper.selectByCondition(scoreEnglish,scoreMath);
        System.out.println(students);
        
        //方法2.使用第二种方法定义参数时使用
        Student student = new Student();
        student.setScoreEnglish(scoreEnglish);
        student.setScoreMath(scoreMath);

        List<Student> students = studentMapper.selectByCondition(student);
        System.out.println(students);
        
        //方法3.使用第三种方法定义参数时使用
        Map map = new HashMap();
        map.put("scoreEnglish" , scoreEnglish);
        map.put("scoreMath" , scoreMath);
        
        List<Student> students = studentMapper.selectByCondition(map);
        System.out.println(students);
        //5. 释放资源
        sqlSession.close();
    }
}

Using three methods to execute the program, the results are the same, as shown in the figure:

image-20230129224312015

5.4 Dynamic SQL

Above we set three parameters in the multi-condition query, and passed in three parameters when executing the test program. However, the reality is that the user may not enter a value for each parameter, and at this time there is a problem with the above sql.

When the user enters two parameters, the SQL statement is as follows:

select * from student where score_english > #{scoreEnglish} and score_math > #{scoreMath};

When the user only enters one condition, the sql statement is as follows:

select * from student where score_english > #{scoreEnglish} ;

For this problem, MyBatis has a powerful solution:

  • if
  • choose(when,otherwise)
  • trim(where,set)
  • foreach

For example, use the following method to solve:

<select id="selectByCondition" resultMap="studentResultMap">
     select * from student 
     where
        <if test="scoreEnglish !=null">
              score_english > #{scoreEnglish}
        </if>
		<if test="scoreMath !=null">
              and score_math > #{scoreMath}
        </if>

</select>

Using this method, strings will be dynamically spliced ​​when the program is executed. If both data are passed in, the sql statement splicing is as follows:

image-20230129231539021

And if the user does not pass in the latter value, then the program is also executed normally, the sql string at this time:

image-20230129231659101

But if the former has no input data and only the latter has given data, the program will have an error, because when splicing sql strings, and will appear after where, and the sql syntax error will occur at this time. as follows:

select * from student where and scoreMath > ? ;//语法错误

This problem can be solved by using the where tag, which can replace the where keyword, and the and after the first condition will be dynamically removed. If all parameters have no given value, the where keyword will not be used.

Note: At this point, you need to add the and keyword to each condition, and the and <where>after the first condition will be dynamically removed.

At this point, the program executes successfully and satisfies the problem that the user may not input values ​​for all parameters. As shown in the picture:

image-20230129232606376

6. Single-condition query of dynamic SQL

In the client, sometimes the user can choose a conditional query, but the Java code does not know which condition to choose, so it is necessary to use the single conditional query of dynamic sql.

Such a requirement can be implemented using the choose(when,otherwise)tag , and the use of the choose tag is similar to the Switch statement in Java.

6.1 Writing interface methods

The single-condition query method of writing dynamic sql in the Mapper interface:

List<Student> selectByConditionSingle(Map map);

6.2 Write sql statement

Write sql statements in the sql mapping configuration file, as follows:

<mapper>    
    <select id="selectByConditionSingle" resultMap="studentResultMap">

        select * from student
        <where>
            <choose>
                <when test="scoreEnglish !=null">
                    score_english > #{scoreEnglish}
                </when>
                <when test="scoreMath !=null">
                    score_math > #{scoreMath}
                </when>
                <otherwise>
                    1=1
                </otherwise>
            </choose>
        </where>
    </select>
</mapper>

6.3 Writing test methods

Write the unit test code in the MyBatisTest class, as follows:

@Test
    public void testSelectByConditionSingle() throws IOException {
    
    
        //接收参数
        int scoreEnglish=60;
        int scoreMath=60;
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3. 获取Mapper接口的代理对象
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        Map map = new HashMap();
        map.put("scoreEnglish" , scoreEnglish);
        //map.put("scoreMath" , scoreMath);

        List<Student> students = studentMapper.selectByConditionSingle(map);
        System.out.println(students);
        //5. 释放资源
        sqlSession.close();
    }

The running result is correct, as shown in the figure:

image-20230130013053973

7. Summary

This article is a practical exercise of MyBatis development and use of configuration files to implement addition, deletion, modification, and query operations. Due to the length of the article, this article only involves query operations. As the most common method of operating databases, query operations must be practiced continuously to become proficient. When writing SQL, although capitalization is not emphasized, it is recommended to use uppercase, because capitalization is a more standardized SQL method.

Finished writing, I checked the time, it is now two o'clock in the morning, I just finished writing this article, and it was extraordinarily quiet outside. Creation is not easy, I hope it can help you. Like it first, watch it later, make it a habit, and see you in the next issue.

image-20230130001121015

Guess you like

Origin blog.csdn.net/zhangxia_/article/details/128796222