Mybatis Learning 03-Multi-table query and lazy loading and use of cache

Environmental preparation

  1. Create database tables user, account, role, and user_role

    DROP TABLE IF EXISTS `user`;
    
    CREATE TABLE `user` (
      `id` int(11) NOT NULL auto_increment,
      `username` varchar(32) NOT NULL COMMENT '用户名称',
      `birthday` datetime default NULL COMMENT '生日',
      `sex` char(1) default NULL COMMENT '性别',
      `address` varchar(256) default NULL COMMENT '地址',
      PRIMARY KEY  (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');
    
    DROP TABLE IF EXISTS `account`;
    
    CREATE TABLE `account` (
      `ID` int(11) NOT NULL COMMENT '编号',
      `UID` int(11) default NULL COMMENT '用户编号',
      `MONEY` double default NULL COMMENT '金额',
      PRIMARY KEY  (`ID`),
      KEY `FK_Reference_8` (`UID`),
      CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `users` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert  into `account`(`ID`,`UID`,`MONEY`) values (1,57,1000),(2,56,1000),(3,57,2000);
    
    DROP TABLE IF EXISTS `role`;
    
    CREATE TABLE `role` (
      `ID` int(11) NOT NULL COMMENT '编号',
      `ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
      `ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
      PRIMARY KEY  (`ID`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert  into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
    
    DROP TABLE IF EXISTS `user_role`;
    
    CREATE TABLE `user_role` (
      `UID` int(11) NOT NULL COMMENT '用户编号',
      `RID` int(11) NOT NULL COMMENT '角色编号',
      PRIMARY KEY  (`UID`,`RID`),
      KEY `FK_Reference_10` (`RID`),
      CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
      CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert  into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);
    
  2. Create entity classes User, Account and Role under the domain layer

    package com.chenpeng.domain;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    
    public class User implements Serializable {
        private Integer id;
        private String username;
        private Date birthday;
        private String sex;
        private String address;
    
        //一对多关系映射,主表实体应该包含从表实体的集合应用
        private List<Account> accounts;
    
        public List<Account> getAccounts() {
            return accounts;
        }
        
        public void setAccounts(List<Account> accounts) {
            this.accounts = accounts;
        }
        
        //多对多关系映射
        private List<Role> roles;
    
        public List<Role> getRoles() {
            return roles;
        }
    
        public void setRoles(List<Role> roles) {
            this.roles = roles;
        }
        
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", birthday=" + birthday +
                    ", sex='" + sex + '\'' +
                    ", address='" + address + '\'' +
                    '}';
        }
    }
    
    package com.chenpeng.domain;
    
    import java.io.Serializable;
    
    public class Account implements Serializable {
        private Integer id;
        private Integer uid;
        private Double money;
        
        //多对一关系映射,从表实体应该包含主表实体的引用
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public Integer getUid() {
            return uid;
        }
    
        public void setUid(Integer uid) {
            this.uid = uid;
        }
    
        public Double getMoney() {
            return money;
        }
    
        public void setMoney(Double money) {
            this.money = money;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", uid=" + uid +
                    ", money=" + money +
                    '}';
        }
    }
    
    package com.chenpeng.domain;
    
    import java.io.Serializable;
    import java.util.List;
    
    public class Role implements Serializable {
        private Integer id;
        private String roleName;
        private String roleDesc;
        
        //多对多关系映射
        private List<User> users;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getRoleName() {
            return roleName;
        }
    
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    
        public String getRoleDesc() {
            return roleDesc;
        }
    
        public void setRoleDesc(String roleDesc) {
            this.roleDesc = roleDesc;
        }
    
        public List<User> getUsers() {
            return users;
        }
    
        public void setUsers(List<User> users) {
            this.users = users;
        }
    
        @Override
        public String toString() {
            return "Role{" +
                    "id=" + id +
                    ", roleName='" + roleName + '\'' +
                    ", roleDesc='" + roleDesc + '\'' +
                    '}';
        }
    }
    
  3. Create the main configuration file SqlMapConfig.xml in the resources directory

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 引入Mybatis的xml约束 -->
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--Mybatis的主配置文件-->
    <configuration>
        <!--配置properties-->
        <properties url="file:///C:/Users/chenpeng/IdeaProjects/Mybatis/src/main/resources/jdbcConfig.properties">
        </properties>
        <!--使用typeAliases配置别名,它只能配置domain中类的别名-->
        <typeAliases>
            <package name="com.chenpeng.domain"/>
        </typeAliases>
        <!--配置环境-->
        <environments default="mysql">
            <!--配置mysql的环境-->
            <environment id="mysql">
                <!--配置事务的类型-->
                <transactionManager type="JDBC"></transactionManager>
                <!--配置数据源(连接池)-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <package name="com.chenpeng.dao"/>
        </mappers>
    </configuration>
    

Multi-table query

Many-to-one query

Implement many-to-one query

  1. Define the query method in the AccountDao interface of the dao layer

    public interface AccountDao {
        /**
         * 查询所有账户同时包含对应的用户信息
         * @return
         */
        List<Account> findAll();
    }
    
  2. Add configuration in AccountDao.xml

    <?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="com.chenpeng.dao.AccountDao">
        <resultMap id="accountUserMap" type="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
            <!--多对一的关系映射,配置封装user的内容-->
            <association property="user" column="uid" javaType="user">
                <id property="id" column="id"></id>
                <result property="username" column="username"></result>
                <result property="birthday" column="birthday"></result>
                <result property="sex" column="sex"></result>
                <result property="address" column="address"></result>
            </association>
        </resultMap>
        <!--查询所有账户同时包含对应的用户信息-->
        <select id="findAll" resultMap="accountUserMap">
            select u.*,a.id as aid,a.uid,a.money from users u,account a where u.id = a.uid
        </select>
    </mapper>
    

One-to-many query

Implement one-to-many query

  1. Define the query method in the UserDao interface of the dao layer

    public interface UserDao {
        /**
         * 查询所有用户同时包含对应的账户信息
         * @return
         */
        List<User> findAll();
    }
    
  2. Add configuration in UserDao.xml

    <?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="com.chenpeng.dao.UserDao">
        <resultMap id="userAccountMap" type="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
            <!--配置user对象中accounts集合的映射-->
            <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>
        <!--查询所有用户同时包含对应的账户信息-->
        <select id="findAll" resultMap="userAccountMap">
            select u.*,a.id as aid,a.uid,a.money from users u left outer join account a on u.id = a.uid
        </select>
    </mapper>
    

Many-to-many query

Implement many-to-many queries

  1. Query all users also contain the corresponding role information

    1. Define the query method in the UserDao interface of the dao layer

      public interface UserDao {
          /**
           * 查询所有用户同时包含对应的角色信息
           * @return
           */
          List<User> findAll();
      }
      
    2. Add configuration in UserDao.xml

      <resultMap id="userMap" type="user">
              <id property="id" column="id"></id>
              <result property="username" column="username"></result>
              <result property="birthday" column="birthday"></result>
              <result property="sex" column="sex"></result>
              <result property="address" column="address"></result>
              <!--配置user对象中roles集合的映射-->
              <collection property="roles" ofType="role">
                  <id property="id" column="roleid"></id>
                  <result property="roleName" column="role_name"></result>
                  <result property="roleDesc" column="role_desc"></result>
              </collection>
          </resultMap>
          <!--查询所有用户同时包含对应的角色信息-->
          <select id="findAll" resultMap="userMap">
              select u.*,ur.*,r.id as roleid,r.role_name,role_desc from users u
              left outer join user_role ur on ur.uid = u.id
              left outer join role r on r.id = ur.rid
          </select>
      
  2. The role used in the query also contains the corresponding user information

    1. Define the query method in the dao layer interface RoleDao

      public interface RoleDao {
      
          /**
           * 查询所有角色同时包含用户的信息
           * @return
           */
          List<Role> findAll();
      }
      
    2. Add configuration in RoleDao.xml

      <?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="com.chenpeng.dao.RoleDao">
      
          <resultMap id="roleMap" type="role">
              <id property="id" column="id"></id>
              <result property="roleName" column="role_name"></result>
              <result property="roleDesc" column="role_desc"></result>
              <collection property="users" ofType="user">
                  <id property="id" column="userid"></id>
                  <result property="username" column="username"></result>
                  <result property="birthday" column="birthday"></result>
                  <result property="sex" column="sex"></result>
                  <result property="address" column="address"></result>
              </collection>
          </resultMap>
          <select id="findAll" resultMap="roleMap">
              select r.*,ur.*,u.id as userid,u.username,u.birthday,u.sex,u.address from role r
              left outer join user_role ur on r.id = ur.rid
              left outer join users u on ur.uid = u.id
          </select>
      </mapper>
      

Lazy loading

What is lazy loading

  • Only when the data is actually used, the query is initiated. What is not used is no query. It is loaded on demand, also called lazy loading.
  • In multi-table queries, one-to-many and many-to-many usually use lazy loading

What is loading immediately

  • Whether it is used or not, as soon as the method is called, the query is initiated immediately
  • In multi-table queries, many-to-one and one-to-one usually use immediate loading

Implement lazy loading

Turn on Mybatis lazy loading

Add configuration in Mybatis main configuration file SqlMapConfig.xml

<!--配置mybatis延迟加载的全局开关-->
    <settings>
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

Lazy loading of many-to-one queries

  1. Dao layer interface method for defining main table query and attached table query

    • Define the query method findAll () in AccountDao

      public interface AccountDao {
          /**
           * 查询所有账户
           * @return
           */
          List<Account> findAll();
      }
      
    • Define the query method findById () in UserDao

      public interface UserDao {
          /**
           * 根据id查询用户
           * @param id
           * @return
           */
          User findById(Integer id);
      }
      
  2. Configure the above two query methods in the configuration file

    • Add configuration in AccountDao

      <?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="com.chenpeng.dao.AccountDao">
          <resultMap id="accountUserMap" type="account">
              <id property="id" column="id"></id>
              <result property="uid" column="uid"></result>
              <result property="money" column="money"></result>
              <!--多对一的关系映射,配置封装user的内容-->
              <association property="user" column="uid" javaType="user" select="com.chenpeng.dao.UserDao.findById">
              </association>
          </resultMap>
          <!--查询所有-->
          <select id="findAll" resultMap="accountUserMap">
              select * from account
          </select>
      </mapper>
      
    • Add configuration in UserDao.xml

      <select id="findById" parameterType="int" resultType="user">
          select * from users where id = #{uid}
      </select>
      

One-to-many lazy loading

  1. Dao layer interface method for defining main table query and attached table query

    • Define the query method in UserDao

      public interface UserDao {
          /**
           * 查询所有用户
           * @return
           */
          List<User> findAll();
      }
      
    • Define the query method in AccountDao

      public interface AccountDao {
          /**
           * 根据用户id查询账户
           * @return
           */
          List<Account> findByUid(Integer uid);
      }
      
  2. Configure the above two query methods in the configuration file

    • Add configuration in UserDao.xml

      <?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="com.chenpeng.dao.UserDao">
          <resultMap id="userMap" type="user">
              <id property="id" column="id"></id>
              <result property="username" column="username"></result>
              <result property="birthday" column="birthday"></result>
              <result property="sex" column="sex"></result>
              <result property="address" column="address"></result>
              <!--配置user对象中accounts集合的映射-->
              <collection property="accounts" ofType="account" column="id" select="com.chenpeng.dao.AccountDao.findByUid">
              </collection>
          </resultMap>
          <!--查询所有-->
          <select id="findAll" resultMap="userMap">
              select * from users
          </select>
      </mapper>
      
    • Add configuration in AccountDao

      <!--根据用户id查询账户-->
          <select id="findByUid" resultType="account" parameterType="int">
              select * from account where uid = #{uid}
          </select>
      

Cache in Mybatis

What is cache

  • Refers to data temporarily stored in memory

What kind of data can use cache

  • Query frequently, the data does not change frequently, and the accuracy of the data does not greatly affect the results

What kind of data can not use cache

  • The data changes frequently, and the accuracy of the data has a great influence on the results

Level 1 cache in Mybatis

  • The first-level cache in Mybatis is the cache of the SqlSession object in Mybatis. When we execute the query, the results of the query will be stored in an area provided by SqLSession (the structure of the area is a map collection)

  • When we query the same data again, Mybatis will first go to the SqLSession to check if there is any, and if so, take it out directly

  • When the SqLSession object disappears, the first-level cache of Mybatis also disappears

  • Test first level cache

    • Define the test method in UserTest

      @Test
          public void testFirstCache(){
              User user = userDao.findById(41);
              System.out.println(user);
              User user1 = userDao.findById(41);
              System.out.println(user1);
              System.out.println(user == user1);
          }
      
    • The output is

      com.chenpeng.domain.User@4bb4de6a
      com.chenpeng.domain.User@4bb4de6a
      true
      

      The user object of the two queries is the same

  • Trigger to clear the first-level cache: When calling the SqlSession object's modify, add, delete, commit () and close () methods, it will clear the first-level cache

Second-level cache in Mybatis

  • The secondary cache in Mybatis is the cache of the SqlSessionFactory object, and the SqlSession object created by the same SqlSessionFactory object shares its cache

Steps for using secondary cache

  1. Let the Mybatis framework support secondary cache

    Add configuration in the main configuration file SqlMapConfig.xml

    <settings>
          <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. Make the current mapping file support second-level cache

    Add configuration in UserDao.xml

    <!--开启user支持二级缓存-->
        <cache></cache>
    
  3. Let the current query method support secondary cache

    In <select>add tag useCacheattributes

    <select id="findById" parameterType="int" resultType="user" useCache="true">
         select * from users where id = #{uid}
    </select>
    
  4. Test the secondary cache

    Define test method

    @Test
        public void testSecondCache(){
            SqlSession sqlSession1 = factory.openSession();
            UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
            User user1 = userDao1.findById(58);
            System.out.println(user1);
    
            SqlSession sqlSession2 = factory.openSession();
            UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
            User user2 = userDao2.findById(58);
            System.out.println(user2);
            System.out.println(user1);
            System.out.println(user1 == user2);
        }
    

    The output is

    com.chenpeng.domain.User@aecb35a
    com.chenpeng.domain.User@4bb4de6a
    false
    

    The user object of the two queries is different. This is because the cache of the SqlSessionFactory object stores data instead of objects. During the second query, the SqlSessionFactory only encapsulates the cached data into the User, so the two are different.

Guess you like

Origin www.cnblogs.com/codeDD/p/12699067.html