Java Xiaobai Practice Manual-Phase 5-MyBatis Framework (day03)

table of Contents

MyBatis

Solve the problem of not being able to encapsulate data caused by inconsistent names by customizing aliases during query

Use the resultMap node to solve the problem of not being able to encapsulate data caused by inconsistent names

One-to-one related query

One-to-many relational query

MyBatis stage summary


MyBatis

Solve the problem of not being able to encapsulate data caused by inconsistent names by customizing aliases during query

Suppose, t_groupinsert some test data into the user group data table ( ) table:

INSERT INTO t_group (name) VALUES ('超级管理员'), ('VIP用户'), ('普通用户');
INSERT INTO t_group (name) VALUES ('禁用用户');

Next, you should t_useradd a new field in the user data table ( ) to record which group each user belongs to:

ALTER TABLE t_user ADD COLUMN group_id int;

Then, assign groups to existing data:

UPDATE t_user SET group_id=1 WHERE id IN (11);
UPDATE t_user SET group_id=2 WHERE id IN (9, 10);
UPDATE t_user SET group_id=3 WHERE id IN (2, 6, 13);

When new fields are added to the user data table, the Userclasses in the project should also add new attributes:

package cn.tedu.mybatis;
​
public class User {
​
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String phone;
    private String email;
    private Integer groupId;
    
    // Setters & Getters
    // toString()
    
}

When you try to query the data again, you will find that the groupIdvalue of each piece of data in the query result is the same null. In fact, these data are all valuable in the database, but the current query function does not detect them!

When MyBatis processes the query, it will automatically encapsulate the data matching the name. The requirement is that the column name of the query result is the same as the attribute name of the encapsulated result class (in fact, the SET method of the attribute is required to be consistent with it), if the name If they are not the same, the corresponding data cannot be assembled automatically!

Field: Field, the name defined when designing the data table;

Column: column, in the query result, the name of each data is the column name;

Property: properties, global variables declared in the class;

When querying, by default, the column name is the field name, but in the query SQL statement, you can customize the alias, for example:

SELECT id,username,password,age,phone,email,group_id groupId FROM t_user ORDER BY id
则配置为:

<select id="findAll" resultType="cn.tedu.mybatis.User">
    SELECT 
        id, username, password, age, phone, email,
        group_id AS groupId 
    FROM 
        t_user 
    ORDER 
        BY id
</select>

Use the resultMap node to solve the problem of not being able to encapsulate data caused by inconsistent names

If there is no custom alias, if the column name of the query result is inconsistent with the attribute name of the class, you can also customize the <resultMap>node for configuration. The function of this node is to guide MyBatis to encapsulate the queried data!

<!-- id:自定义的名称,将应用于select节点的resultMap属性 -->
<!-- type:封装查询结果的数据类型 -->
<resultMap id="UserMap" type="cn.tedu.mybatis.User">
    <!-- result节点:将查询结果中column列对应的值封装到类的property属性中去 -->
    <result column="id" property="id"/>
    <result column="username" property="username"/>
    <result column="password" property="password"/>
    <result column="age" property="age"/>
    <result column="phone" property="phone"/>
    <result column="email" property="email"/>
    <result column="group_id" property="groupId"/>
</resultMap>
​
<select id="findById" resultMap="UserMap">
    SELECT
        *
    FROM 
        t_user 
    WHERE 
        id=#{id}
</select>

In the above configuration, you need to pay attention: <resultMap>the idattribute value in the node is the attribute value of the <select>node resultMap!

If the query operation that needs to be performed is a single-table data query, during configuration <resultMap>, you don’t need to configure those whose column names are consistent with the attribute names!

When configuring <resultMap>, it is recommended to use the <id>node to configure the primary key at the child level , and then use the <result>node to configure the other, so as to facilitate the realization of cache! MyBatis has two levels of cache. Among them, the level 1 cache of MyBatis is the SqlSession cache, and developers cannot intervene. The level 2 cache is the namespace cache. Once it is turned on, it will act on the entire XML file by default, and it needs to be in the current XML file in advance. Adding a <cache></cache>node means "enable caching". It is necessary to encapsulate the data type of the query result to implement the Serializableinterface. If a query does not need to use the cache, it can also be <select>configured in the node useCache="false". Then, the developer does not need to do it With other configurations, MyBatis will automatically process the cached data, and once the current namespace performs an operation of adding, deleting, or modifying, the cache will be rebuilt!

Summary : Use custom aliases in SQL, and <select>use resultTypethe data type of the specified encapsulation result in SQL, or use an asterisk in SQL to indicate the field list, and configure the <resultMap>node <select>and use it in resultMap, which can solve the inconsistency of the name and the inability to encapsulate the query The result of the question.

One-to-one related query

Suppose there is a demand: query the data of a certain user according to the id, and ask to find out the name of the user group to which the user belongs.

If you want to query the data of a user based on id, the SQL statement that needs to be executed is roughly:

SELECT * FROM t_user WHERE id=?

If you want to find out the name of the group to which the user belongs, you need t_groupto query the associated data table together:

SELECT * FROM t_user LEFT JOIN t_group ON t_user.group_id=t_group.id WHERE id=?

Because of these conditions is associated t_user.group_id=t_group.id, in combination with an asterisk as the field list, so, in the query results, there must group_idand subsequent idproblems field value exactly the same! Since the values ​​of two fields must be exactly the same, you should clearly specify the list of fields to be queried:

SELECT 
    t_user.*,
    t_group.name 
FROM 
    t_user 
LEFT JOIN 
    t_group 
ON 
    t_user.group_id=t_group.id 
WHERE 
    t_user.id=?

When using the MyBatis framework to try to implement the function, there is currently no entity class that can encapsulate the results of the above query, because the attribute design of the entity class is required to correspond to the data table, and the query that needs to be executed here involves 2 tables! You need to create a VO class (Value Object class) to encapsulate the results of this query:

public class UserVO {
    
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String phone;
    private String email;
    private Integer groupId;
    private String groupName;
    
    // Setters & Getters
    // toString()
    
}

The attributes in the entity class need to correspond to the data table;

The attributes in the VO class need to correspond to the query results;

Otherwise, the two types of writing are the same, but the positioning is different.

Develop abstract methods:

UserVO findVOById(Integer id);

Configure SQL mapping:

<select id="findVOById" resultType="cn.tedu.mybatis.UserVO">
    SELECT 
        t_user.id, username, password, age, phone, 
        email, group_id AS groupId,
        t_group.name AS groupName
    FROM 
        t_user 
    LEFT JOIN 
        t_group 
    ON 
        t_user.group_id=t_group.id 
    WHERE 
        t_user.id=#{id}
</select>

After completion, test:

@Test
public void findVOById() {
    Integer id = 10;
    UserVO user = userMapper.findVOById(id);
    System.out.println(user);
}

One-to-many relational query

Suppose there is a demand: query the information of a user group based on the id, and also find out which users the group has, and finally display the information of these users!

The SQL statement that needs to be executed is roughly:

SELECT
    *
FROM 
    t_group
LEFT JOIN
    t_user
ON
    t_group.id=t_user.group_id
WHERE
    t_group.id=1

After querying, you need to use a new VO class to encapsulate the query results, then create a GroupVOclass:

public class GroupVO {
    
    private Integer id;
    private String name;
    private List<User> users;
    
    // Setters & Getters
    // toString()
    
}

In a one-to-many query, MyBatis does not know how to encapsulate the data in the query result! When there is no matching query result, or there is only one query result, no error will be reported, but the data of the query result is incorrect. If there are multiple query results, the following error message will appear:

Caused by: org.apache.ibatis.exceptions.TooManyResultsException:
 Expected one result (or null) to be returned by selectOne(), but found: 2

In order to ensure the correct packaging of query results, it must be used <resultMap>to guide MyBatis packaging! Moreover, in the SQL statement, you need to iddefine an alias to ensure that the name of each column of the query result is different. Otherwise, MyBatis will only fetch data from the top column of the same column name, even if in <resultMap>use, <id>configure the primary key, that when the id value of forwardmost row appears a plurality of data are the same, id duplicate data will not be encapsulated!

The specific configuration is as follows:

<?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="cn.tedu.mybatis.GroupMapper">
​
    <resultMap id="GroupVOMap" type="cn.tedu.mybatis.GroupVO">
        <id column="gid" property="id" />
        <result column="name" property="name"/>
        <!-- collection节点:用于配置1对多的属性 -->
        <!-- ofType属性:集合元素类型 -->
        <collection property="users"
            ofType="cn.tedu.mybatis.User">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
            <result column="age" property="age"/>
            <result column="phone" property="phone"/>
            <result column="email" property="email"/>
            <result column="group_id" property="groupId"/>
        </collection>
    </resultMap>
​
    <select id="findVOById" resultMap="GroupVOMap">
        SELECT
            t_group.id AS gid, name,
            t_user.*
        FROM 
            t_group
        LEFT JOIN
            t_user
        ON
            t_group.id=t_user.group_id
        WHERE
            t_group.id=#{id}
    </select>
​
</mapper>

Note: When configuring a one-to-many query <resultMap>, even if there is data with the same column name and attribute name, it must be configured through the <id>or <result>node!

MyBatis stage summary

  • [Understanding] The main role of the MyBatis framework is to simplify the development of the persistence layer;

  • [Understand] Necessary configuration when using MyBatis:

    • Add dependency: mybatis/ mybatis-spring/ spring-context/ spring-jdbc/ mysql-connector-java(It can also be other database connection jar packages, selected according to the actual situation) / druid(It can also be other database connection pools);

    • Configure the information to connect to the database, such as url, driver-class-name, etc.;

    • Configure the location of the XML file (if you use XML to configure SQL statements);

    • Use the configuration class to read the information connected to the database for configuration DataSource; configure SqlSessionFactoryBean; use the @MapperScanannotation to configure the package where the interface file is located before the declaration of the configuration class ;

  • 【Master】Declaration principles of abstract methods

    • [Return Value Type] If the action is INSERT, DELETE, UPDATEtype of operation, using Integeras the return type, indicates "the number of rows affected", may also be used voidbut are not recommended; you need to perform operations that SELECTtype, using the expected data As the return value type, the type only needs to ensure that the type can encapsulate the query result;

    • [Method name] Custom, but not allowed to be overloaded;

    • [Parameter list] Design according to the parameters in the SQL statement that needs to be executed. You can add the required parameters to the parameter list of the abstract method one by one, or you can use the encapsulated type as a parameter. When the parameter of the abstract method exceeds 1 (For example, 2 or more), you must (should) add a @Paramcomment to each parameter and configure the parameter name.

  • [Master] Configure the SQL statement corresponding to the abstract method

    • Before you can use the statement abstract method @Insert, @Delete, @Update, @Selectnode configuration SQL statements, this approach is not recommended for a longer length of SQL statements, or to configure more functions;

    • The XML file for configuring the SQL statement must be in the folder specified by the configuration;

    • The root node of each XML file is <mapper>where the namespaceattribute is the full name of the corresponding interface;

    • In the child through the XML file <insert>, <delete>, <update>, <select>node configuration SQL statements, each node must be configured idattribute value is the name of an abstract method;

    • If you need to obtain the auto-numbered id value after inserting the data, you need to <insert>configure useGeneratedKeysand keyPropertyattribute the node ;

    • In the <select>node, it must be configured resultTypeto specify the return value type of the abstract method, or configured resultMapto guide MyBatis to encapsulate the query result, and one of these two attributes must be configured;

  • [Understanding] Regarding the usage scenarios and differences of placeholders in #{}and ${}format;

  • [Master] <foreach>the use of dynamic SQL ;

  • [Understand] the use of dynamic SQL <if>and <choose>series nodes;

  • [Master] Solve the problem that MyBatis cannot automatically encapsulate query results due to inconsistent names

    • When customizing the field list, customize the alias to make the name consistent, and just <select>use it in the node resultType;

    • When an asterisk is used to indicate a field list, the configuration is <resultMap>to guide the MyBatis package, and the application configuration <select>is used in the node .resultMap<resultMap>

  • [Understanding] The difference between entity class and VO class;

  • [Master] One-to-many related query and related configuration (for example <resultMap>, the <collection>child node in);

  • [Understand] the basic concept of caching;

  • [Understand] Under what circumstances need to use <resultMap>:

    • When querying, there is a problem that the name does not match, and an asterisk is used to indicate the field list;

    • [Required] Configure one-to-many query;

  • [Understand] Under what circumstances need a custom alias:

    • When querying, there is a problem of name mismatch, and if resultMapyou do not use it , you need to customize the alias;

    • [Required] When there are multiple columns with the same name in the related query, you need to customize the alias to make these column names different.

Guess you like

Origin blog.csdn.net/c202003/article/details/107290446