• 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);
  • 相关阅读:
    关于如何使用Microsoft Word发博客
    使用Word发表博客园博文
    利用Word发布文章到博客
    图解利用Word来发布博客
    [转载]如何将word文档直接发布到新浪博客
    如何用word发布博客文章到新浪|网易|博客园?
    word 2010发布文章到博客园
    使用Word2010发布博客到博客园
    C++ 虚函数表解析
    GlobalAlloca GlobalLock GlobalUnlock函数的作用
  • 原文地址:https://www.cnblogs.com/cw172/p/11682226.html
Copyright © 2020-2023  润新知