The introduction

In the previous article, we introduced the multi-table query. In practice, we often involve the multi-table joint query, but sometimes, we do not use all the query results at once. Let me give two examples:

  • For example, you can query the purchase details of a batch of notebook computers without directly displaying the configuration or price details of each column. You can perform a single table query only when the user needs to retrieve the details of a notebook
  • For example, in a bank, if a user has 50 accounts (for example), and we look up this and the user’s information, the details of all the accounts under this user, obviously, it makes more sense to look it up at the point of use

In response to this situation, a mechanism of lazy loading emerged. Lazy loading (lazy loading), as the name implies, is to delay the loading of some information. This technology also helps us to achieve the mechanism of “query on demand”, in one-to-many, or many-to-many situations

Now that I’m talking about lazy loading, and I’m also talking about load now, it means query as soon as it’s called, whether the user wants it or not, and that’s a good way to do it in many-to-one or one-to-one situations

(1) Necessary preparations

First, configure the basic environment, and then we first prepare two tables in the database

The User table

CREATE TABLE USER (
 `id`			INT(11)NOT NULL AUTO_INCREMENT,
 `username` 	VARCHAR(32) NOT NULL COMMENT 'Username'.`telephone`    VARCHAR(11) NOT NULL COMMENT 'mobile phone'.`birthday`		DATETIME DEFAULT NULL COMMENT 'birthday'.`gender`  		CHAR(1) DEFAULT NULL COMMENT 'gender'.`address` 		VARCHAR(256) DEFAULT NULL COMMENT 'address',
  PRIMARY KEY  (`id`))ENGINE=INNODB DEFAULT CHARSET=utf8;
Copy the code

Account table

CREATE TABLE `account` (
  `ID` int(11) NOT NULL COMMENT 'number'.`UID` int(11) default NULL COMMENT 'User number'.`MONEY` double default NULL COMMENT 'value',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`))ENGINE=InnoDB DEFAULT CHARSET=utf8;
Copy the code

Then create their corresponding entity classes

The User class

public class User implements Serializable {
    private Integer id;
    private String username;
    private String telephone;
    private Date birthday;
    private String gender;
    private String address;
    For one-to-many relational mappings, the primary table entity should contain collection references from the secondary table entities
    privateList<Account> accounts; . Please add get set and toString methods}Copy the code

The Account class

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    The secondary table entity should contain an object reference to the primary table entity
    privateUser user; . Please add get set and toString methods}Copy the code

UserMapper.xml

<?xml version="1.0" encoding="UTF-8"? >

      
<mapper namespace="cn.ideal.mapper.UserMapper">

    <! Define User resultMap-->
    <resultMap id="userAccountMap" type="User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="telephone" column="telephone"></result>
        <result property="birthday" column="birthday"></result>
        <result property="gender" column="gender"></result>
        <result property="address" column="address"></result>
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
    
    <! -- Query all users and display corresponding account information -->
    <select id="findAll" resultMap="userAccountMap">
       SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid;
    </select>

    <! Select * from user by id;
    <select id="findById" parameterType="INT" resultType="User">
        select * from user where id = #{uid}
    </select>
    
</mapper>
Copy the code

Create corresponding methods in both interfaces

public interface AccountMapper {
    /** * query all accounts *@return* /
    List<Account> findAll(a);
}
Copy the code
public interface UserMapper {
    /** * Query information about all users and display all accounts under this user **@return* /
    List<User> findAll(a);

    /** * Query user information by id *@param userId
     * @return* /
    User findById(Integer userId);
}
Copy the code

(1) Lazy loading code implementation

First of all, I will show you the way we used to query users one to one, and we will also query all account information corresponding to users

/** * test query all */
@Test
public void testFindAll(a) {
	List<User> users= userMapper.findAll();
    for (User user : users) {
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -"); System.out.println(user); System.out.println(user.getAccounts()); }}Copy the code

Effect:

In this way, information about users and accounts is queried simultaneously through SQL statements and resultMap

So how do we implement lazy loading as we mentioned above?

This time we choose to query the account and lazily load the user’s information

(1) to modify AccountMapper. XML

The first thing that needs to be modified is the Account mapping configuration file. It can be seen that during the query, a resultMap is still defined, which encapsulates Account first and then associates users through association. The use of select and column implements lazy loading of user information

  • Select is used to specify the SQL statement that needs to be executed for lazy loading. That is, to specify the ID of a select tag pair in an SQL mapping file, we specify the method of querying information by ID in the user
  • Column refers to the associated user information query column, in this case, the primary key of the associated user, i.e., ID
<mapper namespace="cn.ideal.mapper.AccountMapper">
	<! ResultMap encapsulates Account and User
    <resultMap id="userAccountMap" type="Account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <! Select: indicates the unique id of the User. Column: indicates the parameter value required by the User based on the ID.
        <association property="user" column="uid" javaType="User" select="cn.ideal.mapper.UserMapper.findById"></association>
    </resultMap>

    <! SQL > select * from user where user >
    <select id="findAll" resultMap="userAccountMap">
        SELECT * FROM account
    </select>
</mapper>
Copy the code

(2) Test the code for the first time

Let’s just perform all of the query methods for the account and see if we can achieve our results

@Test
public void testFindAll(a){
    List<Account> accounts = accountMapper.findAll();
}
Copy the code

(3) Implementation effect

As you can see, all three SQL statements are executed. Why?

This is because we need lazy loading enabled before we can test the method

(4) Lazy loading function

We can go to the official website, how to configure and enable such a function

After consulting the document, we know that if we want to start the lazy loading function, we need to configure the setting attribute in the total configuration file SQLmapconfig. XML, that is, to set the switch of lazyLoadingEnable to teue. Since it is loaded on demand, So you also need to change the aggressive loading to passive loading (that is, change the aggressive loading to false)

Of course, since the version of MyBatis I imported here is 3.4.5, the default value of this value is false, which is actually not necessary, but we will write it

<settings>
	<setting name="lazyLoadingEnabled" value="true"/>
	 <setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
Copy the code

Note: If you use typeAliases to configure the alias, you must place the typeAliases tag after it

(5) Test again

Only query methods are still executed

@Test
public void testFindAll(a){
    List<Account> accounts = accountMapper.findAll();
}
Copy the code

perform

This time, only one query command was executed

What about when the user wants to see who the user is for each account? This is called query on demand, and you just need to add the corresponding fetch method when testing

@Test
public void testFindAll(a){
    List<Account> accounts = accountMapper.findAll();
    for (Account account : accounts){
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --"); System.out.println(account); System.out.println(account.getUser()); }}Copy the code

To perform a

As you can see, our lazy loading goal has been achieved

conclusion

In the above tests, we have implemented lazy loading. Briefly summarize the steps:

  • 1: Execute the corresponding MAPper method, that is, execute the SQL configuration with the id value of findAll in the preceding example

  • ② : In the program, the lazy loading starts when the getUser() method is called by iterating over the queried accounts

    • List<Account> accounts = accountMapper.findAll();
  • (3) Lazy loading is performed, and the corresponding SQL configuration with the id value of findById in the mapping file is invoked to obtain the information of the corresponding user

As you can see, we can query multiple tables directly by using SQL writing methods such as left outer join

SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid;
Copy the code

However, we can implement our demand query requirements through lazy loading. To sum up, in use, we execute simple SQL first, and then load the query information according to the requirements

At the end

If there is any deficiency in the article, you are welcome to leave a message to exchange, thank friends for their support!

If it helps you, follow me! If you prefer the way of reading articles on wechat, you can follow my official account

We don’t know each other here, but we are working hard for our dreams

A adhere to push original development of technical articles of the public number: ideal more than two days