• Mybatis延迟加载、缓存


    一、延迟加载

    java项目目录结构

    1、一对一延迟加载

    1)创建User和Account实体类(具体代码参见我的之前博客)

    2)创建UserDao接口和AccountDao接口

      UserDao接口:

     1 package sun.dao;
     2 
     3 import sun.domain.User;
     4 
     5 import java.util.List;
     6 
     7 public interface UserDao {
     8     /**
     9      * 查询所有用户和该用户名下的账户信息
    10      * @return
    11      */
    12     List<User> findAll();
    13 
    14     /**
    15      * 根据id查找用户信息
    16      * @param id
    17      * @return
    18      */
    19     User findUserById(Integer id);
    20 
    21 }
    UserDao接口

      AccountDao接口:

     1 package sun.dao;
     2 
     3 import sun.domain.Account;
     4 
     5 import java.util.List;
     6 
     7 /**
     8  * @Classname AccountDao
     9  * @Description TODO
    10  * @Date 2020/9/11 13:13
    11  * @Created by Administrator
    12  */
    13 public interface AccountDao {
    14     /**
    15      * 查询所有账户信息和该账户的所属者
    16      */
    17     List<Account> findAll();
    18 
    19     /**
    20      * 根据id查找账户信息
    21      * @param id
    22      * @return
    23      */
    24     Account findAccountById(Integer id);
    25 
    26 }
    AccountDao接口

    3)创建AccountDao.xml映射配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper
     3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 
     6 <mapper namespace="sun.dao.AccountDao">
     7     <!--封装Account类-->
     8     <resultMap id="accountUserMap" type="account">
     9         <id property="id" column="id"></id>
    10         <result property="uid" column="uid"></result>
    11         <result property="money" column="money"></result>
    12       
    13         <!--延迟加载-->
    14         <association property="user" column="uid" javaType="user" select="sun.dao.UserDao.findUserById"></association>
    15     </resultMap>
    16 
    17     <!--查询所有-->
    18     <select id="findAll" resultMap="accountUserMap">
    19         SELECT * from account
    20     </select>
    21 <?xml version="1.0" encoding="UTF-8"?>
    22 <!DOCTYPE mapper
    23         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    24         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    25 
    26 <mapper namespace="sun.dao.AccountDao">
    27     <!--封装Account类-->
    28     <resultMap id="accountUserMap" type="account">
    29         <id property="id" column="id"></id>
    30         <result property="uid" column="uid"></result>
    31         <result property="money" column="money"></result>
    32 
    33         <!--延迟加载 select表示延时加载时执行的操作-->
    34         <association property="user" column="uid" javaType="user" select="sun.dao.UserDao.findUserById"></association>
    35     </resultMap>
    36 
    37     <!--查询所有-->
    38     <select id="findAll" resultMap="accountUserMap">
    39         SELECT * from account
    40     </select>
    41     <!--根据id查询账户-->
    42     <select id="findAccountById" resultType="account">
    43         SELECT * from account where uid=#{id}
    44     </select>
    45 
    46 </mapper>
    47     <select id="findAccountById" resultType="account">
    48         SELECT * from account where uid=#{id}
    49     </select>
    50 
    51 </mapper>
    52     <select id="findAccountById" resultType="account">
    53         SELECT * from account where uid=#{id}
    54     </select>
    55 
    56 </mapper>
    AccountDao.xml

    4)在主配置文件中配置延时加载设置

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE configuration
     3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
     5 
     6 
     7 <!--mybatis主配置文件-->
     8 <configuration>
     9     
    10     <properties resource="jdbcConfig.properties"></properties>
    11 
    12     <!--设置延时加载-->
    13     <settings>
    14         <setting name="lazyLoadingEnabled" value="true"/>
    15         <setting name="aggressiveLazyLoading" value="false"/>
    16     </settings>
    17 
    18     <typeAliases>
    19         <package name="sun.domain"></package>
    20     </typeAliases>
    21 
    22     <!--配置环境-->
    23     <environments default="mysql">
    24         <!--配置mysql环境-->
    25         <environment id="mysql">
    26             <!--配置事务类型-->
    27             <transactionManager type="JDBC"></transactionManager>
    28             <!--配置数据库连接池-->
    29             <dataSource type="POOLED">
    30                 <!--配置连接数据库的四个基本信息-->
    31                 <property name="driver" value="${jdbc.driver}"></property>
    32                 <property name="url" value="${jdbc.url}"></property>
    33                 <property name="username" value="${jdbc.username}"></property>
    34                 <property name="password" value="${jdbc.password}"></property>
    35             </dataSource>
    36 
    37 
    38         </environment>
    39     </environments>
    40 
    41     <!--指定映射配置文件位置-->
    42     <mappers>
    43         <!--<mapper resource="sun/dao/UserDao.xml"></mapper>-->
    44 
    45         <!--package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class-->
    46         <package name="sun.dao"></package>
    47     </mappers>
    48 </configuration>
    配置主配置文件延时加载设置

    5)测试查询账户时延时加载用户是否生效

     1 package sun.test;
     2 
     3 
     4 import org.apache.ibatis.io.Resources;
     5 import org.apache.ibatis.session.SqlSession;
     6 import org.apache.ibatis.session.SqlSessionFactory;
     7 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     8 import org.junit.After;
     9 import org.junit.Before;
    10 import org.junit.Test;
    11 import sun.dao.AccountDao;
    12 import sun.domain.Account;
    13 
    14 import java.io.IOException;
    15 import java.io.InputStream;
    16 import java.util.List;
    17 
    18 public class AccountTest {
    19 
    20     private InputStream in;
    21     private SqlSession sqlSession;
    22     private AccountDao accountDao;
    23 
    24     @Before
    25     public void init() throws IOException {
    26         // 读取配置文件
    27         in = Resources.getResourceAsStream("SqlMapConfig.xml");
    28         // 创建SqlSessionFactory
    29         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    30         SqlSessionFactory factory = builder.build(in);
    31         // 使用工厂生产sqlsession对象
    32         sqlSession = factory.openSession();
    33         // 使用sqlsession创建UserDao接口代理对象
    34         accountDao = sqlSession.getMapper(AccountDao.class);
    35     }
    36 
    37     @After
    38     public void destory() throws IOException {
    39         sqlSession.commit();
    40         sqlSession.close();
    41         in.close();
    42     }
    43 
    44     @Test
    45     public void findAllTest() {
    46         // 使用代理对象执行方法
    47         List<Account> all = accountDao.findAll();
    48         for (Account account : all) {
    49             System.out.println("----------------");
    50             System.out.println(account);
    51             System.out.println(account.getUser());
    52         }
    53     }
    54 
    55 }
    测试类

    测试结果:

     2、一对多延时加载

    1)同上

    2)同上

    3)创建UserDao.xml映射配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper
     3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 
     6 <mapper namespace="sun.dao.UserDao">
     7     <resultMap id="userAccountMap" type="user">
     8         <id property="id" column="id"></id>
     9         <result property="username" column="username"></result>
    10         <result property="sex" column="sex"></result>
    11         <result property="birthday" column="birthday"></result>
    12         <result property="address" column="address"></result>
    13         <!--封装用户名下的账户信息-->
    14         <!--延迟加载-->
    15         <collection property="accounts" ofType="account" select="sun.dao.AccountDao.findAccountById" column="id"></collection>
    16     </resultMap>
    17 
    18     <!--查询所有-->
    19     <select id="findAll" resultMap="userAccountMap">
    20         SELECT * from user
    21     </select>
    22 
    23     <!--查询指定id用户-->
    24     <select id="findUserById" resultType="user">
    25         SELECT * from user where id=#{id}
    26     </select>
    27 </mapper>
    UserDao.xml

    4)同上

    5)测试类

     1 package sun.test;
     2 
     3 
     4 import org.apache.ibatis.io.Resources;
     5 import org.apache.ibatis.session.SqlSession;
     6 import org.apache.ibatis.session.SqlSessionFactory;
     7 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     8 import org.junit.After;
     9 import org.junit.Before;
    10 import org.junit.Test;
    11 import sun.dao.UserDao;
    12 import sun.domain.User;
    13 
    14 import java.io.IOException;
    15 import java.io.InputStream;
    16 import java.util.Date;
    17 import java.util.List;
    18 
    19 public class UserTest {
    20 
    21     private InputStream in;
    22     private SqlSession sqlSession;
    23     private UserDao userDao;
    24 
    25     @Before
    26     public void init() throws IOException {
    27         // 读取配置文件
    28         in = Resources.getResourceAsStream("SqlMapConfig.xml");
    29         // 创建SqlSessionFactory
    30         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    31         SqlSessionFactory factory = builder.build(in);
    32         // 使用工厂生产sqlsession对象
    33         sqlSession = factory.openSession();
    34         // 使用sqlsession创建UserDao接口代理对象
    35         userDao = sqlSession.getMapper(UserDao.class);
    36     }
    37 
    38     @After
    39     public void destory() throws IOException {
    40         sqlSession.commit();
    41         sqlSession.close();
    42         in.close();
    43     }
    44 
    45     @Test
    46     public void findAllTest() {
    47         // 使用代理对象执行方法
    48         List<User> all = userDao.findAll();
    49         for (User user : all) {
    50             System.out.println("---------------");
    51             System.out.println(user);
    52             System.out.println(user.getAccounts());
    53         }
    54     }
    55 
    56 }
    测试类

    测试结果:

     二、缓存

    java项目目录结构

    1、一级缓存

    概述:一级缓存指的是sqlSession对象的缓存。当第一次查询之后,查询结果会同时存入sqlSession为我们提供的一块区域中,该区域的结构是一个HashMap集合,当我们再次查询相同数据时,mybatis会先去该区域查询是否存在,如果存在直接获取。当sqlSession对象消失,一级缓存也就不存在了。一级缓存默认是开启的。

    原理图:

    1)在domain包下创建User实体类

     1 package sun.domain;
     2 
     3 import java.io.Serializable;
     4 import java.util.Date;
     5 import java.util.List;
     6 
     7 public class User implements Serializable {
     8     private Integer id;
     9     private String username;
    10     private Date birthday;
    11     private String sex;
    12     private String address;
    13 
    14     public Integer getId() {
    15         return id;
    16     }
    17 
    18     public void setId(Integer id) {
    19         this.id = id;
    20     }
    21 
    22     public String getUsername() {
    23         return username;
    24     }
    25 
    26     public void setUsername(String username) {
    27         this.username = username;
    28     }
    29 
    30     public Date getBirthday() {
    31         return birthday;
    32     }
    33 
    34     public void setBirthday(Date birthday) {
    35         this.birthday = birthday;
    36     }
    37 
    38     public String getSex() {
    39         return sex;
    40     }
    41 
    42     public void setSex(String sex) {
    43         this.sex = sex;
    44     }
    45 
    46     public String getAddress() {
    47         return address;
    48     }
    49 
    50     public void setAddress(String address) {
    51         this.address = address;
    52     }
    53 
    54 }
    User实体类

    2)在dao包下创建UserDao接口

     1 package sun.dao;
     2 
     3 import sun.domain.User;
     4 
     5 import java.util.List;
     6 
     7 public interface UserDao {
     8     /**
     9      * 查询所有用户和该用户名下的账户信息
    10      * @return
    11      */
    12     List<User> findAll();
    13 
    14     /**
    15      * 根据id查询用户
    16      * @param id
    17      * @return
    18      */
    19     User findUserById(Integer id);
    20 
    21 }
    UserDao接口

    3)测试进行相同的两次查询时获取对象是否是同一个

     1 package sun.test;
     2 
     3 
     4 import org.apache.ibatis.io.Resources;
     5 import org.apache.ibatis.session.SqlSession;
     6 import org.apache.ibatis.session.SqlSessionFactory;
     7 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     8 import org.junit.After;
     9 import org.junit.Before;
    10 import org.junit.Test;
    11 import sun.dao.UserDao;
    12 import sun.domain.User;
    13 
    14 import java.io.IOException;
    15 import java.io.InputStream;
    16 import java.util.Date;
    17 import java.util.List;
    18 
    19 public class firstLevelCacheTest {
    20 
    21     private InputStream in;
    22     private SqlSession sqlSession;
    23     private UserDao userDao;
    24 
    25     @Before
    26     public void init() throws IOException {
    27         // 读取配置文件
    28         in = Resources.getResourceAsStream("SqlMapConfig.xml");
    29         // 创建SqlSessionFactory
    30         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    31         SqlSessionFactory factory = builder.build(in);
    32         // 使用工厂生产sqlsession对象
    33         sqlSession = factory.openSession();
    34         // 使用sqlsession创建UserDao接口代理对象
    35         userDao = sqlSession.getMapper(UserDao.class);
    36     }
    37 
    38     @After
    39     public void destory() throws IOException {
    40         sqlSession.commit();
    41         sqlSession.close();
    42         in.close();
    43     }
    44 
    45     @Test
    46     public void findOneTest(){
    47         User user1 = userDao.findUserById(41);
    48         System.out.println(user1);
    49         User user2 = userDao.findUserById(41);
    50         System.out.println(user2);
    51         System.out.println(user1==user2);
    52     }
    53 
    54 }
    测试类

    测试结果:

     4)调用sqlSession对象的clearCache方法清理一级缓存

     1 package sun.test;
     2 
     3 
     4 import org.apache.ibatis.io.Resources;
     5 import org.apache.ibatis.session.SqlSession;
     6 import org.apache.ibatis.session.SqlSessionFactory;
     7 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     8 import org.junit.After;
     9 import org.junit.Before;
    10 import org.junit.Test;
    11 import sun.dao.UserDao;
    12 import sun.domain.User;
    13 
    14 import java.io.IOException;
    15 import java.io.InputStream;
    16 import java.util.Date;
    17 import java.util.List;
    18 
    19 public class firstLevelCacheTest {
    20 
    21     private InputStream in;
    22     private SqlSession sqlSession;
    23     private UserDao userDao;
    24 
    25     @Before
    26     public void init() throws IOException {
    27         // 读取配置文件
    28         in = Resources.getResourceAsStream("SqlMapConfig.xml");
    29         // 创建SqlSessionFactory
    30         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    31         SqlSessionFactory factory = builder.build(in);
    32         // 使用工厂生产sqlsession对象
    33         sqlSession = factory.openSession();
    34         // 使用sqlsession创建UserDao接口代理对象
    35         userDao = sqlSession.getMapper(UserDao.class);
    36     }
    37 
    38     @After
    39     public void destory() throws IOException {
    40         sqlSession.commit();
    41         sqlSession.close();
    42         in.close();
    43     }
    44 
    45     @Test
    46     public void findOneTest(){
    47         User user1 = userDao.findUserById(41);
    48         System.out.println(user1);
    49         User user2 = userDao.findUserById(41);
    50         System.out.println(user2);
    51         System.out.println(user1==user2);
    52     }
    53 
    54     @Test
    55     public void findOneClearCacheTest(){
    56         User user1 = userDao.findUserById(41);
    57         System.out.println(user1);
    58 //        调用sqlSession对象的clearCache方法清理一级缓存
    59         sqlSession.clearCache();
    60         User user2 = userDao.findUserById(41);
    61         System.out.println(user2);
    62         System.out.println(user1==user2);
    63     }
    64 
    65 }
    清理一级缓存

    测试结果:

     一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。 

     2、二级缓存

    概述:指的是mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession对象共享该缓存。

    1)在 SqlMapConfig.xml 文件开启二级缓存

     <settings>
         <!-- 开启二级缓存的支持 --> 
         <setting name="cacheEnabled" value="true"/>
     </settings>
     因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存

    2)配置相关的 Mapper 映射文件

    <cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
    <?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.itheima.dao.IUserDao">   <!-- 开启二级缓存的支持 -->   <cache></cache> </mapper>

    3)配置 statement 上面的 useCache 属性

    <!-- 根据 id 查询 --> 
    <select id="findById" resultType="user" parameterType="int" useCache="true">   select * from user where id = #{uid} </select>
    将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。 注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

    4)测试

    package sun.test;
    
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    import sun.dao.UserDao;
    import sun.domain.User;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class secondLevelCacheTest {
    
        private InputStream in;
        private SqlSessionFactory factory;
    
        @Before
        public void init() throws IOException {
            // 读取配置文件
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            // 创建SqlSessionFactory
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            factory = builder.build(in);
    
        }
    
        @After
        public void destory() throws IOException {
            in.close();
        }
    
        @Test
        public void findOneTest(){
            SqlSession sqlSession1 = factory.openSession();
            UserDao userDao1 = sqlSession1.getMapper(UserDao.class);
            User user1 = userDao1.findUserById(41);
            System.out.println(user1);
            sqlSession1.close(); // 一级缓存消失 二级缓存启动
    
            SqlSession sqlSession2 = factory.openSession();
            UserDao userDao2 = sqlSession2.getMapper(UserDao.class);
            User user2 = userDao2.findUserById(41);
            System.out.println(user2);
            sqlSession2.close();
    
            System.out.println(user1==user2);
        }
    
    }
    View Code

     问题:虽然二级缓存已经生效,但是两次取出的结果为什么是false?

    答:因为SqlSessionFactory中的二级缓存存储的是数据信息,不是对象信息。因此每次从缓存中获取数据都会重新封装成新的对象。

  • 相关阅读:
    Javascript进阶(7)---函数参数
    Django连接mssql(SqlServer)
    ORM查询
    Django-Model操作数据库
    Django去操作已经存在的数据库
    如何设置CentOS 7获取动态及静态IP地址
    nginx代理设置
    Django+Linux+Uwsgi+Nginx项目部署文档
    nginx的安装部署
    Django项目在linux系统中虚拟环境部署
  • 原文地址:https://www.cnblogs.com/sun-10387834/p/13656885.html
Copyright © 2020-2023  润新知