延迟加载和查询缓存(一级缓存和二级缓存)

延迟加载

当我们执行某些查询操作时,如果可以先查询出一些简单的满足需求,然后当需要某部分时再去查询关联数据,这就叫做延迟加载,这样做可以提高数据库性能

1.需求,例如我们拿以前的例子,查询订单的同时关联查询下单用户,这个关联查询用户的那一部分我们让它延迟加载

2.针对不同的需求编写不同的resultMap,根据不同的对应关系选择association或者collection

3.这里从订单角度出发,订单和下单用户是一对一关系,那么就是使用association

4.实现步骤
1.编写两个statement
2.编写只查询订单的statement
3.编写关联查询用户的statement

 <!--只查询订单信息-->
    <select id="OrdersUserLazyLoading" resultMap="findOrdersUserLazyLoading">
        select * from orders
    </select>

    <!--编写延迟加载resultMap-->
    <resultMap id="findOrdersUserLazyLoading" type="orders">
        <!--编写订单映射-->
        <id column="id" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>
        <!-- 实现对用户信息进行延迟加载
            select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
            要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,
            如果findUserById不在本mapper中需要前边加namespace
            column:订单信息中关联用户信息查询的列,是user_id(外键关联这个user表的id)
            关联查询的sql理解为:
            SELECT orders.*,
            (SELECT username FROM USER WHERE orders.user_id = user.id)username,
            (SELECT sex FROM USER WHERE orders.user_id = user.id)sex
             FROM orders
         -->
        <association property="user"  javaType="user"
                     select="com.lfm.mapper.UserMapper.findUserById" column="user_id">
            <!-- 实现对用户信息进行延迟加载 -->
        </association>
    </resultMap>

4.去SqlMapConfig中配置打开延迟加载(默认是不开启的)
在这里插入图片描述
5.编写测试类测试
在这里插入图片描述
6.debug查看结果
在这里插入图片描述
按F8下一步
在这里插入图片描述
总结如下:
使用延迟加载方法,先去查询简单的sql(最好单表,也可以关联查询),再去按需要加载关联查询的其它信息。

查询缓存

和hibernate一样,mybatis同样有一级缓存和二级缓存,这都是用于减轻数据压力,提高数据库性能。
对于mybatis而言,缓存如下图所示
在这里插入图片描述
1.一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

2.二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

实现一级缓存(默认打开的)

用一个例子测试一下就知道了,就拿根据id查询用户信息来测试把,两次都发送相同的sql语句就会触发缓存
mapper.xml文件编写如下
在这里插入图片描述
mapper接口
在这里插入图片描述
测试类
在这里插入图片描述
结果
在这里插入图片描述
如果在两次查询操作之间发生了数据修改呢?没关系,mybatis有个刷新缓存机制,会保持缓存中的数据都是最新的,我们可以测试一下,在两次查询操作中将id=1的用户更新了第二次再查询
1.写个更新sql
在这里插入图片描述
2.测试类
在这里插入图片描述
3.结果
在这里插入图片描述
总结:一级缓存是在SqlSession范围中的,当SqlSession销毁的时候缓存就已经不存在了,如果想要销毁之后仍然能够在其它地方用到这个SqlSession中的缓存,那么就应该开启二级缓存

二级缓存(手动开启)

原理如下
在这里插入图片描述
1.开启二级缓存
在这里插入图片描述
2.还要在想要使用二级缓存的mapper.xml文件中开启二级缓存,这样整个mapper开算是开启了二级缓存
在这里插入图片描述
3.相应的po类还要实现序列化接口,因为二级缓存数据存储介质多种多样,不一定在内容,有可能在硬盘,所以实现该接口为了以后能够反序列化
在这里插入图片描述
测试方法
在这里插入图片描述
结果
在这里插入图片描述
如果中途数据发生改变呢?
在这里插入图片描述
查看结果
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

禁用二级缓存

只需要在select标签加上useCache="false"即可

刷新缓存

设置statement配置中的flushCache=“true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读,一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。

最后说一下mybatis整合其它分布式缓存框架

因为mybatis本身是不支持分布式缓存的,这样就不能在集群上实现一些功能了,例如用户在服务器A登录了,但是如果不用分布式缓存的话,服务器B并不知道A登录了。所以mybatis要整合第三方的分布式缓存框架,例如redis、memcached、ehcache

这里说一下整合ehcahe
1.导入jar包
在这里插入图片描述
2.mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
在这里插入图片描述
这是mybatis的默认实现
在这里插入图片描述
3.配置mapper中cache中的type为ehcache对cache接口的实现类型
在这个包下找到
在这里插入图片描述
在这里插入图片描述
4.配置ehcache的文件
在这里插入图片描述
上面的信息都可以在ehcache核心包中找到,会出现找不到xsd,百度就可解决了不难
在这里插入图片描述
5.用上面的测试类测试一下,手动改回数据库信息,结果如下

DEBUG [main] - Created connection 479397964.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - ==>  Preparing: select * from user where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User{id=1, username='廖子默', sex='男', birthday=Fri Aug 16 00:00:00 CST 2019, address='广东'}
DEBUG [main] - put added 0 on heap
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Returned connection 479397964 to pool.
DEBUG [main] - Cache Hit Ratio [com.lfm.mapper.UserMapper]: 0.5
DEBUG [main] - Cache Hit Ratio [com.lfm.mapper.UserMapper]: 0.3333333333333333
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 479397964 from pool.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - ==>  Preparing: update user set username=? where id=? 
DEBUG [main] - ==> Parameters: 廖子默66(String), 1(Integer)
DEBUG [main] - cleared heap usage
/******此处省略大概一百个DEBUG [main] - cleared heap usage和DEBUG [main] - cleared disk usage**********/
DEBUG [main] - put added 0 on heap
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Returned connection 479397964 to pool.
DEBUG [main] - Cache Hit Ratio [com.lfm.mapper.UserMapper]: 0.25
DEBUG [main] - Opening JDBC Connection
DEBUG [main] - Checked out connection 479397964 from pool.
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - ==>  Preparing: select * from user where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <==      Total: 1
User{id=1, username='廖子默66', sex='男', birthday=Fri Aug 16 00:00:00 CST 2019, address='广东'}
DEBUG [main] - put added 0 on heap
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c93084c]
DEBUG [main] - Returned connection 479397964 to pool.

Process finished with exit code 0

二级缓存应用场景

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。

二级缓存局限性

mybatis二级缓存对细粒度的数据级别的缓存实现不好,不能针对庞大的缓存数据中只清空需要修改的数据。

延迟加载和缓存本来就是性能优化的手段,不是一朝一夕能搞定的,现在这是照搬基础,等以后活学活用了再回来补充

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值