MyBatis延迟加载和缓存

1、MyBatis延迟加载

1.1、一对一延迟加载

  • 延迟加载,都是针对在多表查询情况下,对关联对象的操作。

用户和订单从面向对象的角度来说就是关联对象,当只需要订单数据,暂时不需要用户数据的时候,就不应该去查询用户表,啥时候用到用户数据,啥时候查询。

  • 一对一延迟加载
    • 对关联查询的SQL语句进行拆分
  • association标签:
    • column属性:关联查询的外键列名
    • select属性:指定另一个< select >标签的id值

IOrdersMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bdit.mapper.IOrdersMapper">

    <select id="findAllOrders" resultMap="ordersUserResult">
        SELECT o.id,o.user_id,o.number,o.createTime,o.note FROM t_orders o
    </select>

    <resultMap id="ordersUserResult" 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"/>
        <!--
        association联合标签,实现手动映射
        property 属性:封装的pojo对象
        javaType属性:封装的pojo对象的类型
        一对一延迟加载:
        column属性:外键列
        select属性:指定另一个查询语句的id值
        -->
        <association property="user" javaType="user" column="user_id"  select="com.bdit.mapper.IUserMapper.findById">
            <id column="id" property="id"/>
            <result column="username" property="username"/>
        </association>
    </resultMap>
<!--    <select id="queryUserByUserId" parameterType="int" resultType="user">-->
<!--        select u.id,u.username,u.email,u.source,u.remark from t_user u where id=#{user_id}-->
<!--    </select>-->


</mapper>

mybatis-config.xml 开启延迟加载配置

<settings>
        <!--开启延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--在mybatis中,默认情况下只要调用了equals,clone,hashCode,toString这几个方法,都会对对象进行完全加载
            lazyLoadTriggerMethods用来指定方法,按需加载,多个方法之间用逗号隔开。
        -->
        <setting name="lazyLoadTriggerMethods" value="getUser"/>
    </settings>
package com.bdit;

import com.bdit.mapper.IOrdersMapper;
import com.bdit.pojo.Orders;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class UserOrdersTest {
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @Before
    public void init() throws IOException {
        InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();
        sqlSessionFactory= sqlSessionFactoryBuilder.build(inputStream);
        sqlSession=sqlSessionFactory.openSession();
    }
    @After
    public void destory(){
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 订单查询用户 ,一对一
     */
    @Test
    public void testOrdersListUser(){
        IOrdersMapper ordersMapper=sqlSession.getMapper(IOrdersMapper.class);
        List<Orders> ordersList=ordersMapper.findAllOrders();
        for(Orders order:ordersList){
            System.out.println(order);
            System.out.println("---------------"+order.getUser());
        }
    }


}

1.2、一对多延迟加载

根据用户查询订单,一对多,延迟加载,拆分SQL语句

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bdit.mapper.IUserMapper">

    <select id="findById" parameterType="int" resultType="user">
        select *
        from t_user where id=#{id};
    </select>

    <!--一对多 用户查询订单  延迟加载-->
    <select id="queryUserOrderList" resultMap="userOrdersResult">
        SELECT u.id,u.username,u.email,u.source,u.remark FROM t_user u

    </select>
    <resultMap id="userOrdersResult" type="user">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="email" column="email"/>
        <result property="source" column="source"/>
        <result property="remark" column="remark"/>
        <!--
            collection标签
                property属性:封装对应的属性名
                ofType属性:指定集合中的泛型类型
        -->
        <collection property="ordersList" ofType="orders" column="id" select="queryOrdersByUserId">
<!--            <id column="order_id" property="id"/>-->
<!--            <result column="user_id" property="userId"/>-->
<!--            <result column="number" property="number"/>-->
<!--            <result column="createTime" property="createTime"/>-->
<!--            <result column="note" property="note"/>-->
        </collection>
    </resultMap>
    <select id="queryOrdersByUserId" parameterType="int" resultType="orders">
        select o.id ,o.user_id as userId,o.number,o.createTime,o.note from t_orders o where user_id=#{user_id}
    </select>
</mapper>
 /**
     * 用户查询订单  一对多
     */
    @Test
    public void queryUserOrdersList(){
        IUserMapper userMapper=sqlSession.getMapper(IUserMapper.class);
        List<User> list=userMapper.queryUserOrderList();
        for(User user:list){
            System.out.println(user);
            for(Orders orders:user.getOrdersList()){
                System.out.println(orders);
            }
        }
    }

2、MyBatis缓存机制

2.1、缓存机制

  • 几乎所有的ORM框架都提供了缓存机制。
  • MyBatis框架包含了一个非常强大的缓存特性,它可以很方便的配置和定制。缓存可以极大地提升查询效率。
  • MyBatis框架中定义了两极缓存
    • 一级缓存
    • 二级缓存
  • 默认情况下,只有一级缓存是开启的,一级缓存就是SqlSession级别的缓存
  • 二级缓存需要手动开启和配置,它是基于namespace级别的缓存
  • 为了提高扩展性,MyBaits定义了缓存接口,可以整合第三方的二级缓存插件。

2.2、一级缓存

一级缓存是SqlSession级别的缓存,只要SqlSession没有flush或close,它就有效。

2.2.1、 证明一级缓存的存在

/**
     * 证明一级缓存的存在,也就是sqlSession级别的缓存
     */
    @Test
    public void queryUserById(){
        IUserMapper userMapper=sqlSession.getMapper(IUserMapper.class);
        User user1= userMapper.findById(9);
        System.out.println(user1);
        //手动清空缓存
        //sqlSession.clearCache();

        User user2=userMapper.findById(9);
        System.out.println(user2);


    }

通过测试可以发现,我们虽然执行了两次查询,但是只执行了一次SQL语句,这就是SqlSession的一级缓存的作用。缓存中如果存在相同条件的数据,直接获取缓存中已存在的;如果缓存中没有符合条件的数据,就会执行SQL语句查询数据库。

2.2.2、 一级缓存的分析

一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit、close方法时,就会清空一级缓存。

第一次查询用户id为9的用户信息,先去缓存中查找是否有id为9的用户信息,如果没有,从数据库中查询用户信息,得到用户信息,并且会将用户信息存储到一级缓存中。如果SqlSession去执行commit操作(执行插入、修改、删除),就会清空SqlSession中的一级缓存,这样做的目的是为了让缓存中的数据永远都是最新的,避免脏读。

2.3、二级缓存

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

2.3.1 二级缓存的开启和关闭

Step1:在mybatis-config.xml文件中开启二级缓存,默认也是开启的,这一步可以省略

<setting name="cacheEnabled" value="true"/>

Step2:在UserMapper.xml中开启针对当前mapper映射文件的二级缓存

  <!--
        cache标签表示当前这个Mapper映射将使用二级缓存,开启二级缓存
    -->
    <cache/>

Step3: 在statement上配置useCache属性

 <!--
        cache标签表示当前这个Mapper映射将使用二级缓存,开启二级缓存
    -->
    <cache/>
    <!--
        useCache="true"代表当前这个statement要使用二级缓存,如果不使用二级缓存就设置成false或者不写
    -->
    <select id="findById" parameterType="int" resultType="user" useCache="true">
        select *
        from t_user where id=#{id};
    </select>
IUserMapper userMapper=sqlSession.getMapper(IUserMapper.class);
        User user1= userMapper.findById(9);
        System.out.println(user1);
        sqlSession.commit();
        sqlSession.close();
        //手动清空缓存
        //sqlSession.clearCache();
        SqlSession sqlSession1=sqlSessionFactory.openSession();
        IUserMapper userMapper2=sqlSession1.getMapper(IUserMapper.class);
        User user2=userMapper2.findById(9);
        System.out.println(user2);
        sqlSession1.commit();
        sqlSession1.close();

2.3.2 二级缓存的注意事项

当我们使用MyBatis中的二级缓存时,所缓存的对象一定要实现序列化接口

在实际开发中MyBatis的二级缓存应用很少

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值