• MyBatis延迟加载和缓存


    一、延迟加载

    1.主对象的加载:

    根本没有延迟的概念,都是直接加载。

    2.关联对象的加载时机:

    01.直接加载:

    访问主对象,关联对象也要加载

    02.侵入式延迟:

    访问主对象,并不加载关联对象

    访问主对象属性的属性的时候,关联对象会被加载

    03.深度延迟

    访问主对象,并不加载关联对象

    访问主对象的属性的时候,关联对象也不会被加载

    访问关联对象或关联对象的属性的时候,才会加载关联对象。

    3.一对多延迟加载代码:

    01.实体类代码:

    package cn.pb.bean;
    
    import java.util.Set;
    
    /**
     * 国家的实体类
     */
    public class Country {
        private Integer cId;//国家的编号
        private String cName;//国家的名称
    
        //关联省会的属性
        private Set<Provincial> provincials;
    
        public Integer getcId() {
            return cId;
        }
    
        public void setcId(Integer cId) {
            this.cId = cId;
        }
    
        public String getcName() {
            return cName;
        }
    
        public void setcName(String cName) {
            this.cName = cName;
        }
    
        public Set<Provincial> getProvincials() {
            return provincials;
        }
    
        public void setProvincials(Set<Provincial> provincials) {
            this.provincials = provincials;
        }
    
       
    }
    package cn.pb.bean;
    
    /**
     * 省会对应的实体类
     */
    public class Provincial {
        private Integer pId;    //省会的编号
        private String pName;  //省会名称
    
        public Integer getpId() {
            return pId;
        }
        public void setpId(Integer pId) {
            this.pId = pId;
        }
        public String getpName() {
            return pName;
        }
        public void setpName(String pName) {
            this.pName = pName;
        }
    }

    02.dao层代码:

    public interface CountryDao {
    /**
     * 根据国家id 查询国家的信息 以及国家下面的省会
     */
    Country selectCountryById(Integer id);
    }    

    03.mapper.xml代码:

    <mapper namespace="cn.pb.dao.CountryDao">
      <!--01.先根据id查询出国家信息 多条sql的查询 可以使用延迟加载策略-->
        <select id="selectCountryById" resultMap="countryMap">
            select cid,cname from country where cid=#{xxx}
        </select>
      <!--03.根据国家id 查询出省份信息 -->
        <select id="selectProvincialByCountryId" resultType="Provincial">
            select pid,pname from provincial
            where countryid=#{xxx}
            <!--#{xxx} 对应的就是resultMap中 collection节点下面的column -->
        </select>
    
      <!--02.国家的映射信息-->
        <resultMap id="countryMap" type="Country">
            <id property="cId" column="cid"/>
            <result property="cName" column="cname"/>
            <!--设置关联的集合属性
             select:需要关联的查询语句
            column: select关联语句中需要的参数 -->
            <collection property="provincials" ofType="Provincials"
                        select="selectProvincialByCountryId"
                        column="cid"/>
        </resultMap>
    
        
    </mapper>

    04.测试代码:

    public class CountryTest {
        CountryDao dao=null;
        SqlSession session=null;
        Logger log= Logger.getLogger(CountryTest.class);
    
        @Before
        public void before(){
    
            //获取session
            session= SessionFactoryUtil.getSession();
            //获取执行的类对象
            dao=session.getMapper(CountryDao.class);
        }
    
        /**
         * 在所有的test测试方法执行之后 都要执行的操作
         */
        @After
        public void after(){
            if(session!=null){
                session.close();
            }
        }
    
      <!--只输出主加载对象 只会有一条sql语句-->
        @Test
        public void testSelectCountryById(){
            Country country=dao.selectCountryById(1);
            log.debug("根据id查询国家信息"+country);
        }
    
      
      <!--输出关联对象的信息 会有两条sql语句-->
        @Test
        public void testSelectCountryById(){
            Country country=dao.selectCountryById(1);
            log.debug("根据id查询国家信息"+country.getProvincials());
        }
    
    }

    4.配置延迟加载:

    在mybatis.xml文件中配置:

    <settings>
    <!-- 全局性地启用或禁用延迟加载。当禁用时,所有关联的配置都会立即加载。 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--当启用后,一个有延迟加载属性的对象的任何一个延迟属性被加载时,该对象
    的所有的属性都会被加载。否则,所有属性都是按需加载。 侵入式延迟 -->
    <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

    二、MyBatis缓存

    1.查询缓存的作用:

    查询缓存的使用,主要是为了提供查询访问速度。将用户对同一数据的重复查询过程简化,不再每次均从数据库查询获取结果数据,从而提高访问速度。

    2.关于缓存的说明:

    01.MyBatis查询缓存机制。根据缓存区的作用域与生命周期,可划分为两种:一级缓存和二级缓存。

    02.MyBatis查询缓存的作用域是根据映射文件的namespace划分的,相同的namespace的mapper查询数据放在同一个缓存区域。不同namespace下的数据互不干扰。无论是一级缓存还是二级缓存,都是按照namespace进行分别存放的。

    03.但是一级、二级缓存的不同之处在于,SqlSession一旦关闭,则SqlSession中的数据将不存在,即一级缓存就不复存在。而二级缓存的生命周期与整个应用同步,与SqlSession是否关闭无关。换句话说,一级缓存是在同一线程(同一SqlSession)间共享数据,而二级缓存是在不同线程(不同的SqlSession)间共享数据。

    04. 一级缓存: 基于PerpetualCache 的 HashMap本地缓存,其生命周期为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。

    05. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。

    06. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

    3.一级缓存:

    01.一级缓存存在的证明代码:

    001.dao层代码:

    /**
     * 根据学生的编号查询对应的信息
     * 验证一级缓存的存在
     */
    Student selectStudentById(Integer sId);

    002.mapper.xml代码:

    <mapper namespace="cn.pb.dao.StudentDao">
        <!-- 查询指定学生的信息    验证一级缓存的存在 -->
        <select id="selectStudentById" resultType="Student">
            select sid,sname from stu where sid=#{xxx}
        </select>
    </mapper>

    003.测试代码:

    package cn.pb;
    
    
    import cn.pb.bean.Student;
    import cn.pb.dao.StudentDao;
    import cn.pb.util.SessionFactoryUtil;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.log4j.Logger;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    public class StudentTest {
        StudentDao dao;
        SqlSession session;
        Logger logger=Logger.getLogger(StudentDao.class);
        @Before
        public void before(){
            session= SessionFactoryUtil.getSession();
            dao=session.getMapper(StudentDao.class);
        }
    
        /**
         * 在所有的test测试方法执行之后 都要执行的操作
         */
        @After
        public void after(){
            if(session!=null){
                session.close();
            }
        }
    
    
        /**
         * 验证一级缓存的存在
         * myBatis的一级缓存是一直开启的,并且不能关闭!
         */
        @Test
        public void test1(){
            Student student=dao.selectStudentById(1);
            logger.debug("第一次查到的id为1的学生:"+student);
            //再次查询相同的id对象
            Student student2 = dao.selectStudentById(1);
            logger.debug("第2次查到的id为1的学生:"+student2);
        }
    }

    02.一级缓存--从缓存中查找数据的依据:

    001.缓存的底层实现是一个Map,Map的value是查询结果

    002.Map的key,即查询依据,使用的ORM架构不同,查询依据是不同的

    003.MyBatis的查询依据是:Sql的id+SQL语句

    004.Hibernate的查询依据是:查询结果对象的id

    005.验证代码:

    a.dao层代码:

    /**
    * 验证mybatis缓存查询的依据!
    */
    Student selectStudentById2(Integer sId);
    b.mapper.xml代码:
    <mapper namespace="cn.pb.dao.StudentDao">
       
        <!-- 查询指定学生的信息    验证mybatis缓存查询的依据!
                 两个查询语句的id不一致,但是sql语句一样-->
        <select id="selectStudentById2" resultType="Student">
            select  sid,sname from  stu where sid=#{xxx}
        </select>
    
       
    </mapper>

    c.测试代码:

    /**
     * 验证查询的依据
     * 两个查询都是查询id为1的学生对象,但是查询语句的id不一致
     */
    
    @Test
    public void test2() {
        Student student = dao.selectStudentById(1);
        logger.debug("第1次查到的id为1的学生:"+student);
        //再次查询相同的id对象
        Student student2 = dao.selectStudentById2(1);
        logger.debug("第2次查到的id为1的学生:"+student2);
    }
    得到的结论是:
    mybatis的查询依据是 : mapper文件中sql的id + sql语句!
    hibernate底层查询的依据是: 查询对象的id!

    其实缓存的底层是一个map,
    map的key就是查询依据,value是查询的结果!



    03.增、删、改对一级缓存的影响:

    增删改会清空一级缓存:注意:必须使用insert标签,不能使用select,否则实验做不成功

    001.dao层代码:

    /**
     * 验证增删改查对一级缓存的影响!
     */
    void addStudent(Student student);
  • 相关阅读:
    Balanced Binary Tree
    Convert Sorted List to Binary Search Tree
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Validate Binary Search Tree
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Maximum Depth of Binary Tree
    如何把U盘的两个盘或者多个盘合成一个
    bugku 想蹭网先解开密码
  • 原文地址:https://www.cnblogs.com/cw172/p/11682226.html
Copyright © 2020-2023  润新知