mybatis延迟加载和缓存

一、mybatis延迟加载

1、延迟加载概述

(1)延迟加载又叫懒加载,也叫按需加载。也就是说先加载主信息,在需要的时候,再去加载从信息

(2)在mybatis中,resultMap标签 的association标签和collection标签具有延迟加载的功能。

2、延迟加载案例分析

(1)需求:查询订单信息,关联查询用户信息
a、创建一个statement来查询订单信息
b、创建一个statement来查询用户信息
(2)映射文件:

    
    <resultMap type="ordersExt" id="lazyLoadingRstMap">
        
        <id column="id" property="id" />
        <result column="user_id" property="userId" />
        <result column="number" property="number" />
        
        
        
        
        <association property="user"
            select="com.san.mapper.UserMapper.findUserById" column="user_id">association>
    resultMap>

    
    <select id="findOrderAndUserLazyLoading" resultMap="lazyLoadingRstMap">
        SELECT * FROM
        orders
    select>

创建查询用户信息的映射文件:


    <select id="findUserById" parameterType="int" resultType="com.san.po.User">
        SELECT
        * FROM USER WHERE id =#{id}
    select>

(3)mapper接口:

    //延迟加载
    public List findOrderAndUserLazyLoading();

(4)测试代码:

    //懒加载
    @Test
    public void Test01() throws IOException{
        // 读取配置文件
        // 全局配置文件的路径
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 创建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 创建OrdersMapper对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
        List list = mapper.findOrderAndUserLazyLoading();
        //按需加载时,是需要的时候再去查询数据库
        for (OrdersExt ordersExt : list) {
            System.out.println(ordersExt.getUser());
        }
        sqlSession.close();
    }

(5)设置延迟加载:
在SqlMapConfig.xml中,配置settings标签

    <settings>
        
        <setting name="lazyLoadingEnabled" value="true"/>

        
        <setting name="aggressiveLazyLoading" value="false"/>

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

二、mybatis一级缓存

1、mybatis缓存理解

(1)Mybatis的缓存,包括一级缓存和二级缓存,一级缓存是默认使用的,二级缓存需要手动开启。

(2)一级缓存指的就是sqlsession,在sqlsession中有一个数据区域,是map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。

(3)二级缓存指的就是同一个namespace下的mapper,二级缓存中,也有一个map结构,这个区域就是一级缓存区域。一级缓存中的key是由sql语句、条件、statement等信息组成一个唯一值。一级缓存中的value,就是查询出的结果对象。

(4)图解:
mybatis延迟加载和缓存_第1张图片

2、一级缓存原理

mybatis延迟加载和缓存_第2张图片

3、一级缓存测试

(1)测试1:

@Test
//一级缓存测试1
public void Test01() throws Exception{
    //全局配置文件
    String resource="SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //创建Mapper对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    //第一次查询
    User user1=userMapper.findUserById(1);
    System.out.println(user1);
    //第二次查询
    User user2=userMapper.findUserById(1);
    System.out.println(user2);
    //关闭资源
    sqlSession.close();
}

(2)测试2:

@Test
//一级缓存测试2
public void Test02() throws Exception{
    //全局配置文件
    String resource="SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //创建mapper对象
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //第一次查询
    User user1=mapper.findUserById(1);
    System.out.println(user1);

    //执行添加用户操作
    mapper.insertUser(user1);
    //执行commit操作,将一级缓存清空
    sqlSession.commit();

    //第二次查询
    User user2=mapper.findUserById(1);
    System.out.println(user2);
}

(3)解释:
mybatis延迟加载和缓存_第3张图片

三、mybatis二级缓存

1、二级缓存原理

mybatis延迟加载和缓存_第4张图片

2、二级缓存测试

(1)开启二级缓存:
a、开启二级缓存的总开关


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

b、在mapper映射文件中开启二级缓存


<cache/>

(2)序列化:
二级缓存,需要序列化是因为需要将缓存的数据写入硬盘

public class User implements Serializable

(3)测试1:

@Test
//二级缓存测试1
public void Test01() throws Exception{
    String resource="SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();

    //由mybatis通过sqlSession来创建代理对象
    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);

    //第一次查询
    User user1=mapper1.findUserById(1);
    System.out.println(user1);
    //在close的时候,才会将数据写入二级缓存中
    sqlSession1.close();

    //第二次查询
    User user2=mapper2.findUserById(1);
    System.out.println(user2);
    sqlSession2.close();

}

mybatis延迟加载和缓存_第5张图片
(4)测试2:

@Test
//二级缓存测试2
public void Test02() throws Exception{
    String resource="SqlMapConfig.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    SqlSession sqlSession3 = sqlSessionFactory.openSession();

    //由mybatis通过sqlSession来创建代理对象
    UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);

    //第一次查询
    User user1=mapper1.findUserById(1);
    System.out.println(user1);
    //在close的时候,才会将数据写入二级缓存中
    sqlSession1.close();

    //执行用户添加操作
    mapper3.insertUser(user1);
    //执行commit时,将一级缓存清空
    sqlSession3.close();


    //第二次查询
    User user2=mapper2.findUserById(1);
    //System.out.println(user2);
    sqlSession2.close();
}

3、其他

(1)禁用缓存:
useCache=”false”

<select id="findUserById" useCache="false" parameterType="int" resultType="com.san.po.User">
        SELECT
        * FROM USER WHERE id =#{id}
    select>

(2)刷新缓存:
flushCache=”true”:刷新缓存,在select语句中,默认值是false,在增删改语句中,默认值是true

<select id="findUserById" flushCache="true" parameterType="int" resultType="com.san.po.User">
        SELECT
        * FROM USER WHERE id =#{id}
    select>

四、整合ehcache

1、ehcache概述

(1)Ehcache是一个分布式的缓存框架

(2)Mybatis本身是一个持久层框架,它不是专门的缓存框架,所以它对缓存的实现不够好,不能支持分布式。

2、分布式概述

(1)系统为了提高性能,通常会对系统采用分布式部署(集群部署方式)

(2)图解:
mybatis延迟加载和缓存_第6张图片

3、整合思路

(1)Cache是一个接口,它的默认实现是mybatis的PerpetualCache。如果想整合mybatis的二级缓存,那么实现Cache接口即可

(2)图解:
mybatis延迟加载和缓存_第7张图片

4、整合步骤

(1)添加jar包
mybatis延迟加载和缓存_第8张图片
(2)设置映射文件中cache标签的type值为ehcache的实现类
mybatis延迟加载和缓存_第9张图片
(3)添加ehcache的配置文件
在config下,创建ehcache.xml


<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    
    <diskStore path="F:\develop\ehcache" />
    

    <defaultCache maxElementsInMemory="1000"
    maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false"
    timeToIdleSeconds="120" timeToLiveSeconds="120"
    diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU">
    defaultCache>
ehcache>

5、其他

(1)应用场景:
对于访问响应速度要求高,但是实时性不高的查询,可以采用二级缓存技术。
注意:在使用二级缓存的时候,要设置一下刷新间隔(cache标签中有一个flashInterval属性)来定时刷新二级缓存,这个刷新间隔根据具体需求来设置,比如设置30分钟、60分钟等,单位为毫秒。

(2)局限性:
Mybatis二级缓存对细粒度的数据,缓存实现不好。
场景:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都是最新的商品信息,此时如果使用二级缓存,就无法实现当一个商品发生变化只刷新该商品的缓存信息而不刷新其他商品缓存信息,因为二级缓存是mapper级别的,当一个商品的信息发送更新,所有的商品信息缓存数据都会清空。
解决此类问题,需要在业务层根据需要对数据有针对性的缓存。
比如可以对经常变化的 数据操作单独放到另一个namespace的mapper中

你可能感兴趣的:(Mybatis)