Mybatis延迟加载、缓存、逆向工程

一、Mybatis中的延迟加载

  1、延迟加载背景:Mybatis中Mapper配置文件中的resultMap可以实现高级映射(使用association、collection实现一对一及一对多(多对多)映射),同样的association、collection具备延迟加载功能。所谓延迟加载,就是先单表查询,需要时再从关联表去关联查询(同样也可能只是是单表查询),大大单表查询速度更快,所以可以间接的提高数据库性能

  2、在mybatis核心配置文件中配置,其中lazyLoadingEnabled表示懒加载开关、aggressiveLazyLoading表示非懒加载(积极加载),通过在Mybatis核心配置文件中配置这些属性的值来使用Mybatis的懒加载,具体配置方式如下:

    <settings>
        <!--懒加载模式在Mybatis中默认是关闭的-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--不同于懒加载的:积极加载方式,所以在懒加载的时候设置该属性为false-->
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>

  3、由于是使用懒加载,所以我们显然可以将Mapper配置文件中的查询分为两张单表查询的statment,其中User表的查询放在Order查询配置的resultMap中,并进行延迟加载的设置

    <select id="findUserByUid" parameterType="int" resultType="cn.mybatis.po.User">
        SELECT * FROM USER WHERE uid = #{id}
    </select>

    <resultMap id="OrderAndUserByLazyLoading" type="cn.mybatis.po.Order">
        <id column="oid" property="oid"></id>
        <result column="total" property="total"></result>
        <result column="ordertime" property="ordertime"></result>
        <result column="name" property="name"></result>

        <!--
            实现延迟加载功能
            select:指定延迟加载需要执行的statment的id(即根据用户id查询用户信息的select的statment)
            column:关联查询的列信息-->
        <association property="user" javaType="cn.mybatis.po.User" select="findUserByUid" column="uid">
        </association>
    </resultMap>

    <select id="findOrderAndUserByLazyLoading" resultMap="OrderAndUserByLazyLoading">
        SELECT * FROM orders
    </select>

LazyLoading配置文件信息

  4、在Mapper.java中添加了延迟加载的测试方法

    //延迟加载测试方法
    public List<Order> findOrderAndUserByLazyLoading() throws Exception;

  5、使用Junit测试延迟加载的测试代码

 1     @Test
 2     public void testFindOrderAndUserByLazyLoading() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
 5
 6         List<Order> orderList= orderMapper.findOrderAndUserByLazyLoading();
 7
 8         for (Order order : orderList) {
 9             System.out.println(order.getUser());
10         }
11
12         sqlSession.close();
13     }

  6、测试结果,从测试结果可以看出,我们首先只是单表查询了order是表的信息,然后在遍历查询到的结果(打印User信息)的时候,又发出查询user信息的Sql,从而实现了延迟加载的功能

二、Mybatis中的一级缓存

  1、一级缓存是在SqlSession 层面进行缓存的。即在同一个SqlSession 中,多次调用同一个Mapper中的同一个statment并且是同一个参数的话,只会进行一次数据库查询,然后把数据缓存到缓冲中,如果以后要查询相同的Sql和参数,就直接先从缓存中取出数据,不会直接去查数据库。? 但是不同的SqlSession对象,因为不用的SqlSession都是相互隔离的,所以相同的Mapper、参数和方法,他还是会再次发送到SQL到数据库去执行,返回结果。(本质上是在SqlSession作用域下面的HashMap本地缓存,当 SqlSession 刷新或 关闭之后,该Session中的所有 缓存数据就将清空。)可以用下面的这张图来表示一级缓存

  2、我们来使用一级缓存进行测试,首先通过上面一级缓存的简单定义,我们可以得到下面的这张简略图,用以示解一级缓存。在实例图中,第一次查询某条记录时候,Mybatis所做的就是将查询到的结果放在该SqlSession的缓存中,如果期间没有该数据的修改、删除、或者增加操作,那么之后再读取该数据就会直接从缓存中得到数据,而不用再向数据库发Sql请求,当然,如果第一次查询之后,对数据进行了delete、update、insert操作,那么就会删除缓存中的数据,这样做的目的也很显然,保证数据的最新性,避免出现脏读的情况。

  3、一级缓存的测试(Mybatis中默认开启的是一级缓存)

  做个简单的测试:按照上面的图中所示,我们查询两次id=1的User信息,并且两次查询期间没有进行会清空缓存的操作,结果应该是只向数据库发送一次Sql查询

 1     @Test
 2     public void testUpdateUserInfo() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 5
 6         User user1 = userMapper.findUserById(1);
 7         System.out.println(user1);
 8
 9         User user2 = userMapper.findUserById(1);
10         System.out.println(user2);
11
12         sqlSession.close();
13     }

  4、我们通过观察日志可以看出,只是在第一次查询的时候发送了Sql,第二次是直接打印user信息

  

  当然,接下来要做的测试就是在两次查询期间做insert操作,然后观察日志,结果应该是发现会想数据库发送两次sql

 1     @Test
 2     public void testUpdateUserInfo() throws Exception {
 3         SqlSession sqlSession = sqlSessionFactory.openSession();
 4         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 5
 6         User user1 = userMapper.findUserById(1);
 7         System.out.println(user1);
 8
 9         User user = new User("InsertTest","insert","insert","man");
10         userMapper.insertUserInfo(user);
11         sqlSession.commit();
12
13         User user2 = userMapper.findUserById(1);
14         System.out.println(user2);
15
16         sqlSession.close();
17     }

  5、我们在测试代码中加了insert之后,通过观察日志可以发现,在查询过程中,向Database发送了两条select语句,可以验证上面的猜想

  

三、Mybatis中的二级缓存

  1、二级缓存的实现机制基本上和一级缓存机制相同,不同的作用域不一样,二级缓存区域在一个个的mapper中。显然,由于多个SqlSession可以操作同一个mapper,所以二级缓存比一级缓存域更大。二级缓存按照mapper划分,简而言之,也可说成按照mapper中的namespace进行划分,这样看来,每一个namespace下面都有一个二级缓存区域,而如果两个mapper的namespace相同,那么数据会缓存在相同的缓存区域中。当然,类似于一级缓存的特点,如果不同的SqlSession进行数据的insert、delete、update操作的话,也会清空二级缓存中的数据

  2、开启二级缓存后,进行测试。具体使用二级缓存在配置文件中的配置为:

  首先在Mybatis的核心配置文件中配置二级缓存(本项目中的SQLMapConfig.xml)

    <!--settings配置二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"></setting>
    </settings>

  然后在需要配置二级缓存的特定mapper配置文件中进行添加二级缓存的配置

  

  3、编写测试程序并运行

 1  @Test
 2     public void testCache() throws Exception {
 3         SqlSession sqlSession1 = sqlSessionFactory.openSession();
 4         UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
 5         User user1 = userMapper1.findUserById(1);
 6         System.out.println(user1);
 7         //需要将SqlSession关闭才能将数据写入缓存
 8         sqlSession1.close();
 9
10
11         SqlSession sqlSession2 = sqlSessionFactory.openSession();
12         UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
13         User user2 = userMapper2.findUserById(1);
14         System.out.println(user2);
15         sqlSession2.close();
16
17
18     }

  在运行的时候出现了下面的异常,原因就是没有实现序列化接口,由于缓存数据可能再本地内存中,也可能在其他存储介质上,所以存在对象的序列化和反序列化

  所以在实现序列化接口之后,再次运行,得到下面的结果

 

原文地址:https://www.cnblogs.com/fsmly/p/10343184.html

时间: 2024-08-28 10:14:34

Mybatis延迟加载、缓存、逆向工程的相关文章

MyBatis延迟加载和缓存

一.延迟加载 1.主对象的加载: 根本没有延迟的概念,都是直接加载. 2.关联对象的加载时机: 01.直接加载: 访问主对象,关联对象也要加载 02.侵入式延迟: 访问主对象,并不加载关联对象 访问主对象属性的属性的时候,关联对象会被加载 03.深度延迟 访问主对象,并不加载关联对象 访问主对象的属性的时候,关联对象也不会被加载 访问关联对象或关联对象的属性的时候,才会加载关联对象. 3.一对多延迟加载代码: 01.实体类代码: package cn.pb.bean; import java.u

Mybatis延迟加载和查询缓存

一.延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快. 在mybatis核心配置文件中配置: lazyLoadingEnabled.aggressiveLazyLoading 设置项 描述 允许值 默认值 lazyLoadingEnabled 全局性设置

mybatis 延迟加载 ,查询缓存

阅读目录 一.延迟加载 二.查询缓存 回到顶部 一.延迟加载 resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 延迟加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快. 在mybatis核心配置文件中配置: lazyLoadingEnabled.aggressiveLazyLoading 设置项 描述 允许值 默认值

mybatis的缓存和注解开发(4)

第四天:mybatis的缓存和注解开发 mybatis中的加载时机(查询的时机) mybatis中的一级缓存和二级缓存 mybatis的注解开发  单表CRUD  多表查询 一.今日内容概要 1.Mybatis中的延迟加载 问题:在一对多中,当我们有一个用户,它有100个账户.       在查询用户的时候,要不要把关联的账户查出来?       在查询账户的时候,要不要把关联的用户查出来?         在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的.       在查询

mybatis查询缓存——(十三)

1.     mybatis缓存介绍 如下图,是mybatis一级缓存和二级缓存的区别图解: mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的. 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个

MyBatis一级缓存、二级缓存

一.MyBatis一级缓存 MyBatis默认启动一级缓存,一级缓存是SqlSession级别的 注意:有两个因素会使一级缓存失效:  1.对SqlSession进行commit()操作(即对数据库进行了增.删.改操作).数据库中的数据发生了改变,此时若再从内存中读取缓存的数据,则会读取到错误的数据信息,所以此时旧的一级缓存中的数据会清空,当用户下一次执行查询操作时, 会重新从数据库中读取数据并放入一级缓存中  2.关闭SqlSession.一级缓存的设计是每个sqlsession单独使用一个缓

深入了解MyBatis二级缓存

深入了解MyBatis二级缓存 标签: mybatis二级缓存 2015-03-30 08:57 41446人阅读 评论(13) 收藏 举报  分类: Mybatis(51)  版权声明:版权归博主所有,转载请带上本文链接!联系方式:[email protected] 目录(?)[+] 深入了解MyBatis二级缓存 一.创建Cache的完整过程 我们从SqlSessionFactoryBuilder解析mybatis-config.xml配置文件开始: Reader reader = Reso

MyBatis 一级缓存与二级缓存

MyBatis一级缓存 MyBatis一级缓存默认开启,一级缓存为Session级别的缓存,在执行以下操作时一级缓存会清空 1.执行session.clearCache(); 2.执行CUD操作 3.session.close(); //不是同一个Session对象了 MyBatis二级缓存 需要配置<cache></cache> 是一个映射文件级的缓存 使用Mybatis二级缓存时查询的对象实体类必须序列化实现(实现Serializable接口) 二级缓存使用时 必须使用sess

Spring+SpringMVC+MyBatis深入学习及搭建(八)——MyBatis查询缓存

1.什么是查询缓存 mybatis提供查询缓存,用于减轻数据库压力,提高数据库性能. mybatis提供一级缓存和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的. 二级缓存是mapper级别的缓存,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存

MyBatis一级缓存引起的无穷递归

MyBatis一级缓存引起的无穷递归 引言: 最近在项目中参与了一个领取优惠劵的活动,当多个用户领取同一张优惠劵的时候,使用了数据库锁控制并发,起初的设想是:如果多个人同时领一张劵,第一个到达的人领取成功,其它的人继续查找是否还有剩余的劵,如果有,继续领取,否则领取失败.在实现中,我一开始使用了递归的方式去查找劵,实际的测试中发现出现了无穷递归,通过degug和查阅资料才发现这是由于mybatis的一级缓存引起的,以下将这次遇到的问题和大家分享讨论. 1.涉及到的知识点 Mybatis缓存: 一