Mybatis Learning 03 - Consulta com várias tabelas e carregamento e uso lento do cache

Preparação ambiental

  1. Crie tabelas de banco de dados usuário, conta, função e 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. Criar classes de entidade Usuário, Conta e Função na camada de domínio

    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. Crie o arquivo de configuração principal SqlMapConfig.xml no diretório de recursos

    <?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>
    

Consulta de várias tabelas

Consulta muitos-para-um

Implementar consulta muitos-para-um

  1. Defina o método de consulta na interface AccountDao da camada dao

    public interface AccountDao {
        /**
         * 查询所有账户同时包含对应的用户信息
         * @return
         */
        List<Account> findAll();
    }
    
  2. Adicionar configuração no 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>
    

Consulta um para muitos

Implementar consulta um para muitos

  1. Defina o método de consulta na interface UserDao da camada dao

    public interface UserDao {
        /**
         * 查询所有用户同时包含对应的账户信息
         * @return
         */
        List<User> findAll();
    }
    
  2. Adicionar configuração no 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>
    

Consulta de muitos para muitos

Implementar consultas muitos para muitos

  1. Consulta a todos os usuários também contém as informações de função correspondentes

    1. Defina o método de consulta na interface UserDao da camada dao

      public interface UserDao {
          /**
           * 查询所有用户同时包含对应的角色信息
           * @return
           */
          List<User> findAll();
      }
      
    2. Adicionar configuração no 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. A função usada na consulta também contém as informações do usuário correspondentes

    1. Defina o método de consulta na interface da camada dao RoleDao

      public interface RoleDao {
      
          /**
           * 查询所有角色同时包含用户的信息
           * @return
           */
          List<Role> findAll();
      }
      
    2. Adicionar configuração no 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>
      

Carregamento lento

O que é carregamento lento

  • Somente quando os dados são realmente usados, a consulta é iniciada, o que não é usado não é consulta, é carregado sob demanda, também chamado de carregamento lento.
  • Nas consultas de várias tabelas, um para muitos e muitos para muitos geralmente usam carregamento lento

O que está carregando imediatamente

  • Seja usada ou não, assim que o método é chamado, a consulta é iniciada imediatamente
  • Em consultas com várias tabelas, muitos para um e um para um geralmente usam carregamento imediato

Implementar carregamento lento

Ativar carregamento lento do Mybatis

Adicionar configuração no arquivo de configuração principal do Mybatis, SqlMapConfig.xml

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

Carregamento lento de consultas muitos-para-um

  1. Método de interface da camada Dao para definir a consulta da tabela principal e a consulta da tabela anexada

    • Defina o método de consulta findAll () em AccountDao

      public interface AccountDao {
          /**
           * 查询所有账户
           * @return
           */
          List<Account> findAll();
      }
      
    • Defina o método de consulta findById () no UserDao

      public interface UserDao {
          /**
           * 根据id查询用户
           * @param id
           * @return
           */
          User findById(Integer id);
      }
      
  2. Configure os dois métodos de consulta acima no arquivo de configuração

    • Adicionar configuração no 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>
      
    • Adicionar configuração no UserDao.xml

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

Carregamento preguiçoso de um para muitos

  1. Método de interface da camada Dao para definir a consulta da tabela principal e a consulta da tabela anexada

    • Defina o método de consulta no UserDao

      public interface UserDao {
          /**
           * 查询所有用户
           * @return
           */
          List<User> findAll();
      }
      
    • Defina o método de consulta no AccountDao

      public interface AccountDao {
          /**
           * 根据用户id查询账户
           * @return
           */
          List<Account> findByUid(Integer uid);
      }
      
  2. Configure os dois métodos de consulta acima no arquivo de configuração

    • Adicionar configuração no 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>
      
    • Adicionar configuração no AccountDao

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

Cache em Mybatis

O que é cache

  • Refere-se a dados armazenados temporariamente na memória

Que tipo de dados pode usar cache

  • Consultar com freqüência, os dados não mudam com frequência e a precisão dos dados não afeta muito os resultados

Que tipo de dados não pode usar cache

  • Os dados são alterados com frequência e a precisão dos dados tem uma grande influência nos resultados

Cache de nível 1 em Mybatis

  • O cache de primeiro nível em Mybatis é o cache do objeto SqlSession em Mybatis.Quando executamos a consulta, os resultados da consulta serão armazenados em uma área fornecida pelo SqLSession (a estrutura da área é uma coleção de mapas)

  • Quando consultamos os mesmos dados novamente, o Mybatis primeiro acessa o SqLSession para verificar se há algum e, se houver, retira-o diretamente

  • Quando o objeto SqLSession desaparece, o cache de primeiro nível de Mybatis também desaparece

  • Teste o cache de primeiro nível

    • Defina o método de teste no 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);
          }
      
    • A saída é

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

      O objeto de usuário das duas consultas é o mesmo

  • Disparador para limpar o cache de primeiro nível: ao chamar os métodos de modificação, adição, exclusão, exclusão (commit) e close () do objeto SqlSession, ele limpará o cache de primeiro nível

Cache de segundo nível em Mybatis

  • O cache secundário em Mybatis é o cache do objeto SqlSessionFactory, e o objeto SqlSession criado pelo mesmo objeto SqlSessionFactory compartilha seu cache

Etapas para usar o cache secundário

  1. Deixe a estrutura Mybatis suportar cache secundário

    Adicionar configuração no arquivo de configuração principal SqlMapConfig.xml

    <settings>
          <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. Faça com que o arquivo de mapeamento atual suporte o cache de segundo nível

    Adicionar configuração no UserDao.xml

    <!--开启user支持二级缓存-->
        <cache></cache>
    
  3. Permitir que o método de consulta atual suporte o cache secundário

    No <select>Tag Adicionar useCacheatributos

    <select id="findById" parameterType="int" resultType="user" useCache="true">
         select * from users where id = #{uid}
    </select>
    
  4. Teste o cache secundário

    Definir método de teste

    @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);
        }
    

    A saída é

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

    O objeto de usuário das duas consultas é diferente. Isso ocorre porque o cache do objeto SqlSessionFactory armazena dados em vez de objetos. Durante a segunda consulta, o SqlSessionFactory apenas encapsula os dados em cache no Usuário, portanto as duas são diferentes.

Acho que você gosta

Origin www.cnblogs.com/codeDD/p/12699067.html
Recomendado
Clasificación