深入浅出Mybatis(九)延迟加载和缓存

在mybatis中,只有resultMap才具有延迟加载的功能。

1.在订单查询中实现对用户信息的延迟加载。

使用association中的select去指定延迟加载需要执行的statement的id。

<!-- 延迟加载的resultMap -->
    <resultMap id="ordersUserLazyLoading" 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(根据statement的id查询到的sql语句)
            要使用userMapper.xml中完成根据用户id(user_id)用户信息的查询
            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.beyond.mybatis.po.User" select="com.beyond.mybatis.mapper.UserMapper.selectUser" column="user_id">
        </association>
    </resultMap>
    <!-- 查询订单关联查询用户信息,延迟加载用户信息 -->
    <select id="findOrdersUserLazyLoading" resultMap="ordersUserLazyLoading">
        select * from orders
    </select>

编写接口方法:

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

编写测试方法:

测试思路:

1、执行上边mapper方法,内部只查询了orders表

2、在程序中遍历上一步骤查询出的List<Orders>,当我们调用Orders中的getUser方法时,开始进行延迟加载。

3、延迟加载,去掉用UserMapper.xml中的selectUser这个方法获取用户信息。

首先:需要在sqlMapConfig.xml中开启延迟加载的开关。

<!-- 全局参数配置 -->
    <settings>
        <!-- 打开延迟加载的开关 -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 将积极加载改为消极加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
@Test
    //查询订单关联查询用户,用户信息延迟加载
    public void testfindOrdersUserLazyLoading() throws Exception{
        SqlSession sqlSession = factory.openSession();
        //通过反射拿到UserMapper的代理对象
        OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class);
        List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading();

        //遍历上边的订单列表
        for (Orders orders: list) {
            User user = orders.getUser();
            System.out.println(user);
        }

    }

collection的用户可以参考association。

缓存:

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

mybatis提供一级缓存和二级缓存。


    一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)

用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互不影响的。


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

二级缓存是跨SqlSession的。

为什么要用缓存?

如果缓存中有数据就不用从数据库中获取,大大提高系统性能。

一级缓存

下面是根据id查询用户的一级缓存:

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

信息。得到用户信息,将用户信息存储到一级缓存中。


如果sqlsession去执行commit操作(插入、更新、删除),清空sqlsession中的一级缓存,这样做的目的是为了

让缓存中存储的是最新的信息,避免脏读。


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

mybatis默认开启了一级缓存。

//一级缓存测试
    public void testCache1() throws Exception{
        SqlSession sqlSession = factory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        //两个都是使用的同一个sqlsession
        //第一次发起请求,查询id为1的用户,从数据看查
        User user1 = userMapper.selectUser(1);
        System.out.println(user1);
        //第二次发起请求,查询id为1的用户,从缓存中取
        User user2 =  userMapper.selectUser(1);
        System.out.println(user2);
    }

二级缓存:


首先开启mybatis的二级缓存

sqlsession1取查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。

sqlsession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

sqlsession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据。

二级缓存与一级缓存区别:二级缓存的范围更大,多个sqlsession可以共享一个userMapper的二级缓存区域。

userMapper有一个二级缓存区域(按namespace分),其他mapper也有自己的二级缓存区域(按namespace分)

每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql

查询到数据将存在相同的二级缓存区域中。

开启二级缓存:

在sqlMapConfig.xml中的settings中加入(默认开启的)

<!-- 开启二级缓存 -->
        <setting name="cacheEnable" value="true"/>

在userMapper.xml中开启二级缓存,userMapper下的sql语句执行完会存储到它的二级缓存中

<mapper namespace="com.beyond.mybatis.mapper.UserMapper">
    
    <!-- 开启本mapper的namespace下的二级缓存 -->
    <cache/> 

调用的pojo类实现序列化接口

为了将缓存数据取出,执行反序列化操作,因为二级缓存的存储介质是多样的,不一定在内存

//二级缓存测试
    public void testCache2() throws Exception{
        SqlSession sqlSession1 = factory.openSession();
        SqlSession sqlSession2 = factory.openSession();
        SqlSession sqlSession3 = factory.openSession();
        UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
        UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);

        //两个都是使用的同一个sqlsession
        //第一次发起请求,查询id为1的用户,从数据看查
        User user1 = userMapper1.selectUser(1);
        System.out.println(user1);

        //这里执行关闭操作,将sqlsession中的数据写到二级缓存中
        sqlSession1.close();

        //使用sqlSession3执行commit操作
        User user3 = userMapper3.selectUser(1);
        user3.setUsername("king");
        userMapper3.updateUser(user3);
        //执行提交,清空UserMapper下边的二级缓存
        sqlSession3.commit();
        sqlSession3.close();

        //第二次发起请求,查询id为1的用户,从缓存中取
        User user2 =  userMapper2.selectUser(1);
        System.out.println(user2);
        sqlSession2.close();
    }

禁用二级缓存

<select id="selectUser" parameterType="int" resultType="user" useCache="false">

对于数据变化比较快的,且每次都要获取最新的可以禁用二级缓存。

刷新缓存:(默认为true)

<update id="updateUser" parameterType="com.beyond.mybatis.po.User" flushCache="true">

使用自定义的缓存。

1.实现cache接口(org.apache.ibatis.cache.Cache)
2.在cache标签中引用。

mybatis整合ehcache

在pom加入ehcache整合mybatis的依赖jar包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.1.0</version>
</dependency>

在UserMapper.xml中引入这个class

 <!-- 开启本mapper的namespace下的二级缓存 -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

猜你喜欢

转载自blog.csdn.net/qq_21963133/article/details/79772085