Mybatis学习(6)动态加载、一二级缓存

一、动态加载:

resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

需求:

如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

需要先说明下是按照这个sql的思路来实现延迟加载的:

mysql> select orders.*, (select user.username from user where orders.user_id = user.id) username from orders;

(对于这种查询,可以分成两部来理解,首先忽略整个select子查询,查出订单表中的数据,然后根据订单表的user_id执行子查询,对于一个orders的user_id,子查询只能返回一条数据,如果子查询返回多条数据则会出错,另外,每一条select子查询只能查询一个字段。)

mapper.xml:

<mapper namespace="com.cy.mapper.OrdersMapperCustom">
    <!-- 延迟加载的resultMap -->
    <resultMap type="com.cy.po.Orders" id="OrdersLazyLoadingUser">
        <id column="id" property="id"></id>
        <result column="user_id" property="userId"></result>
        <result column="number" property="number"></result>
        <result column="createtime" property="createtime"></result>
        <result column="note" property="note"></result>

        <!-- 实现对用户信息进行延迟加载
            select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
            要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,如果findUserById不在本mapper中需要前边加namespace
            column:订单信息中关联用户信息查询的列,是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="com.cy.po.User" column="user_id" select="com.cy.mapper.UserMapper.findUserById">

        </association>
    </resultMap>

    <!-- 查询订单关联查询用户,用户信息需要延迟加载 -->
    <select id="findOrdersLazyLoadingUser" resultMap="OrdersLazyLoadingUser">
        select * from orders;
    </select>
 </mapper>

这边需要配置settings  延迟加载:

<settings>
   <!-- 打开延迟加载 的开关 -->
   <setting name="lazyLoadingEnabled" value="true"/>
   <!-- 将积极加载改为消极加载即按需要加载 -->
   <setting name="aggressiveLazyLoading" value="false"/</settings>

mapper接口:

//查询订单关联查询用户,用户信息是延迟加载
public List<Orders> findOrdersLazyLoadingUser() throws Exception;

测试代码:

// 查询订单关联查询用户,用户信息使用延迟加载
    @Test
    public void FindOrdersLazyLoadingUser() throws Exception {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
        // 查询订单信息(单表)
        List<Orders> orders = ordersMapperCustom.findOrdersLazyLoadingUser();

        for(Orders order: orders){
            // 执行getUser()去查询用户信息,这里实现按需加载
            User user = order.getUser();
            System.out.println(user);
        }
        sqlSession.close();
    }

可以看到console输出的打印语句:

DEBUG [main] - Setting autocommit to false on JDBC Connection [[email protected]]
DEBUG [main] - ==> Preparing: select * from orders;
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 3
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
------->> User [id=1, username=王五, sex=2, birthday=null, address=null]
------->> User [id=1, username=王五, sex=2, birthday=null, address=null]
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id=?
DEBUG [main] - ==> Parameters: 10(Integer)
DEBUG [main] - <== Total: 1
------->> User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [[email protected]]

二、1级缓存、2级缓存:

mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

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

1.一级缓存:

工作原理:

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

测试代码:

一级缓存不需要在配置文件中配置,mybatis默认支持一级缓存;

 1 // 一级缓存测试
 2     @Test
 3     public void testCache1() throws Exception {
 4         SqlSession sqlSession = sqlSessionFactory.openSession();
 5         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 6         // 第一次发起请求,查询id为1的用户
 7         User user1 = userMapper.findUserById(1);
 8         System.out.println(user1);
 9
10         // 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
11         // 更新user1的信息
12         // user1.setUsername("测试用户22");
13         // userMapper.updateUser(user1);
14         // //执行commit操作去清空缓存
15         // sqlSession.commit();
16
17         // 第二次发起请求,查询id为1的用户
18         User user2 = userMapper.findUserById(1);
19         System.out.println(user2);
20
21         sqlSession.close();
22     }

一级缓存测试

时间: 2024-08-11 05:29:16

Mybatis学习(6)动态加载、一二级缓存的相关文章

js的动态加载、缓存、更新以及复用(二)

上一篇发出来后得到了很多回复,在此首先感谢大家的热情捧场!有的推荐第三方框架,比如 In.js.requrieJS.sea.js.lab.js等.这个开阔了眼界,以前只知道sea.js,省去了自己搜索的麻烦.也用了点时间简单看了一下,因为每一个都是大块头,都有自己的理念,如果只是简单使用的话,那么谁便找一个就可以了,但是我习惯把原理弄清楚.因为我觉得虽然不知道原理也可以使用,但是知道了原理后,可以用的更好. 主要看的是sea.js,目前简单的理解是:一个加载js的机制 + 模块化编程(CMD规范

js的动态加载、缓存、更新以及复用(一)

使用范围: OA.MIS.ERP等信息管理类的项目,暂时不考虑网站. 遇到的问题: 完成一个项目,往往需要引用很多js文件,比如jQuery.js.easyUI等.还有自己写的一些列js文件,那么这些文件如何方便的加载,如果文件有变化如何才能让客户端及时更新缓存?如果能够提高点运行效率,那就更好了. 目标: 1.  可以方便的引用js文件. 2.  尽量使用各种缓存,避免频繁从服务器读取文件. 3.  如果js文件有更新或者增加.减少几个减少js文件,需要客户端能够自动.立刻更新. 4.  Js

js的动态加载、缓存、更新以及复用(三)

总体思路 1.  建立一个js服务,该服务实现通用js文件的加载.依赖.缓存.更新以及复用. 2.  各个项目如果使用通用js,可(bi)以(xu)使用js服务实现加载. 3.  Js服务只提供通用的js,比如jQuery.my97.easyUI等(可根据实际情况设定具体的js文件). 4.  其他针对特点需求写的js文件,需要自己写代码加载.Js服务可以提供加载用函数.(正在考虑要不要使用sea.js) 5.  Js服务加载的js文件,不需要做任何修改.当然也不负责各个文件里的函数名称是否冲突

js的动态加载、缓存、更新以及复用

使用范围: OA.MIS.ERP等信息管理类的项目,暂时不考虑网站. 遇到的问题: 完成一个项目,往往需要引用很多js文件,比如jQuery.js.easyUI等.还有自己写的一些列js文件,那么这些文件如何方便的加载,如果文件有变化如何才能让客户端及时更新缓存?如果能够提高点运行效率,那就更好了. 目标: 1.  可以方便的引用js文件. 2.  尽量使用各种缓存,避免频繁从服务器读取文件. 3.  如果js文件有更新或者增加.减少几个减少js文件,需要客户端能够自动.立刻更新. 4.  Js

JS学习之动态加载script和style样式

前提:我们可以把一个网页里面的内容理解为一个XML或者说网页本身也就是一个XML文档,XML文档都有很特殊的象征:"标签"也叫"节点".我们都知道一个基本的网页格式是 <!DOCTYPE /> <head></head> <body><body /> 这些是最基本的形态,但是其实它省略了最外面的一个标签<document>. <document> <!DOCTYPE />

[WPF学习笔记]动态加载XAML

好久没写Blogs了,现在在看[WPF编程宝典],决定开始重新写博客,和大家一起分享技术. 在编程时我们常希望界面是动态的,可以随时变换而不需要重新编译自己的代码. 以下是动态加载XAML的一个事例代码. 在debug文件夹下新建一个文本文件,重命名为:file.xaml 插入界面代码: <DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <Button Name=

[Android学习系列15]下拉刷新列表实现动态加载

使用google官方的SwipeRefreshLayout 参考: http://blog.csdn.net/easyer2012/article/details/22857807 http://stormzhang.github.io/android/2014/03/29/android-swiperefreshlayout/ http://www.eoeandroid.com/thread-330439-1-1.html http://www.oschina.net/translate/sw

atitit.动态加载数据库配置in orm hibernate mybatis

atitit.动态加载数据库配置in orm 1. 动态加载数据库配置的优点::: 1 1.1. 组合多个配置文件... 1 1.2. 连接多个数据库 1 2. 基本的流程:::getCfg内存对象,,,,生成工厂类,在opoenSession 1 2.1. Hibernate动态添加配置流程 1 2.2. mybatis动态添加配置流程 1 2.3. #===hb code 2 3. 参考 3 1. 动态加载数据库配置的优点::: 1.1. 组合多个配置文件... 1.2. 连接多个数据库 2

避免缓存,Java动态加载配置文件

Java动态加载配置文件 关键:每次读取都要重新生成流 今天无意间在项目的代码中看到如下这样一段简单加载配置文件的代码: Properties prop = new Properties(); InputStream in = PropertiesTest.class.getClassLoader().getResourceAsStream("/config.properties"); prop.load(in); 其实代码本身是没有什么问题的 问题就是用这种方式来读取配置文件,会存在