`

Mybatis一级、二级缓存

 
阅读更多

一级缓存

首先做一个测试,创建一个mapper配置文件和mapper接口,我这里用了最简单的查询来演示。

 

 

<mapper namespace="cn.elinzhou.mybatisTest.mapper.UserMapper">

    <select id="findUsers" resultType="cn.elinzhou.mybatisTest.pojo.User">
        SELECT * FROM user
    </select>
</mapper>
 

 

 

public interface UserMapper {
    List<User> findUsers()throws Exception;
}
 

 

 

然后编写一个单元测试

 

public class UserMapperTest {


    SqlSession sqlSession = null;
    @Before
    public void setUp() throws Exception {
        // 通过配置文件获取数据库连接信息
        Reader reader = Resources.getResourceAsReader("cn/elinzhou/mybatisTest/config/mybatis.xml");
        // 通过配置信息构建一个SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        // 通过sqlSessionFactory打开一个数据库会话
        sqlSession = sqlSessionFactory.openSession();
    }

    @Test
    public void testFindUsers() throws Exception {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.findUsers();
        System.out.println(users);
    }
}
 

 

运行,可以看到控制台输出(先配好log4j)为类似如下图日志 
这里写图片描述

日志说明了该操作执行的sql语句已经查询的内容,最后一行是我手动通过System.out.printf输出的结果。

然后再加一条语句

 

users = userMapper.findUsers();
 

之前的单元测试就变成了这个样子

这里写图片描述

也就是在执行完userMapper.findUsers();后立刻再执行一遍userMapper.findUsers(); 可以想象,其实这两个操作执行的sql是完全相同的,而且在这期间没有对数据库进行过其他操作。然后执行该单元测试,发现效果跟上面执行一条的时候完全相同,也就是执行第二次userMapper.findUsers();操作的时候没有对数据库进行查询,那么得到的数据是从哪里来的?答案是一级缓存。

mybatis一级缓存是指在内存中开辟一块区域,用来保存用户对数据库的操作信息(sql)和数据库返回的数据,如果下一次用户再执行相同的请求,那么直接从内存中读数数据而不是从数据库读取。 
其中数据的生命周期有两个影响因素。

  1. 对sqlsession执行commit操作时

对sqlsession执行commit操作,也就意味着用户执行了update、delete等操作,那么数据库中的数据势必会发生变化,如果用户请求数据仍然使用之前内存中的数据,那么将读到脏数据。所以在执行sqlsession操作后,会清除保存数据的HashMap,用户在发起查询请求时就会重新读取数据并放入一级缓存中了。

这里写图片描述

这里写图片描述

上述测试就是在第一查询完后执行了commit操作,再进行查询。与之前的测试不同的是,这次测试控制台打印了两组查询结果,说明在commit之后mybatis对数据重新进行了查询。

  1. 关闭sqlsession

一般在mybatis集成spring时,会把SqlSessionFactory设置为单例注入到IOC容器中,不把sqlsession也设置为单例的原因是sqlsession是线程不安全的,所以不能为单例。那也就意味着其实是有关闭sqlsession的过程的。其实,对于每一个service中的sqlsession是不同的,这是通过mybatis-spring中的org.mybatis.spring.mapper.MapperScannerConfigurer创建sqlsession自动注入到service中的。 
而一级缓存的设计是每个sqlsession单独使用一个缓存空间,不同的sqlsession是不能互相访问数据的。当然,在sqlsession关闭后,其中数据自然被清空。

特此警告!!!! 
当MyBatis与spring整合后,如果没有事务,一级缓存是失效的!一级缓存是失效的!一级缓存是失效的! 
原因就是两者结合后,sqlsession如果发现当前没有事务,那么每执行一个mapper方法,sqlsession就被关闭了。如果需要维持一级缓存的可用性,有两种途径:

  1. 添加事务
  2. 使用二级缓存

二级缓存

在使用二级缓存之前,先测试之前提到过的关闭sqlsession后会清空缓存的问题,把junit代码修改一下

@Test
    public void testFindUsers() throws Exception {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.findUsers();
        //关闭sqlsession
        sqlSession.close();

        //通过sqlsessionFactroy创建一个新的sqlsession
        sqlSession = sqlSessionFactory.openSession();
        //获取mapper对象
        userMapper = sqlSession.getMapper(UserMapper.class);
        users = userMapper.findUsers();
        System.out.println(users);
    }

 

这段代码在第一次查询完后关闭sqlsession,然后创建新的sqlsession和mapper来重新执行一次查询操作,可以预见,执行结果如图

这里写图片描述

说明关闭了sqlsession后的确把之前的缓存数据清空了,之后再执行同样的查询操作也会再访问一遍数据库。为了解决这个问题,需要使用二级缓存

一级缓存的作用域仅限于一个sqlsession,但是二级缓存的作用域是一个namespace。但并不是意味着同一个namespace创建的mapper可以互相读取缓存内容,这里的原则是,如果开启了二级缓存,那么在关闭sqlsession后,会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

接下测试,先需要开启二级缓存。

1.打开二级缓存总开关 
打开总开关,只需要在mybatis总配置文件中加入一行设置

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

 

2.打开需要使用二级缓存的mapper的开关

在需要开启二级缓存的mapper.xml中加入caceh标签

<cache/>

 

3.POJO序列化

让需要使用二级缓存的POJO类实现Serializable接口,如

public class User implements Serializable {

 

通过之前三步操作就可以使用二级缓存了,接下来测试。添加一个Junit方法

@Test
    public void testFindUsersCache() throws Exception {
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = userMapper.findUsers();
        //关闭sqlsession
        sqlSession.close();

        //通过sqlsessionFactroy创建一个新的sqlsession
        sqlSession = sqlSessionFactory.openSession();
        //获取mapper对象
        userMapper = sqlSession.getMapper(UserMapper.class);
        users = userMapper.findUsers();
        System.out.println(users);
    }

 

执行后可以发现,控制台值输出了一次查询过程,也可以证明二级缓存开启成功。

还有一个问题,之前说了,即使开启了二级缓存,不同的sqlsession之间的缓存数据也不是想互访就能互访的,必须等到sqlsession关闭了以后,才会把其一级缓存中的数据写入二级缓存。为了测试这个,把上述代码中的

sqlSession.close();

 

注释,那么之前的代码就变成了 
这里写图片描述

再执行,发现控制太又输出了两次的查询过程,所以可以印证,只有关闭了sqlsession之后,才会把其中一级缓存数据写入二级缓存。

缓存配置

  • 关闭刷新

在默认情况下,当sqlsession执行commit后会刷新缓存,但是也可以强制设置为不刷新,在不需要刷新的标签中加入

flushCache="false" 

 

<select id="findUsers" resultType="cn.elinzhou.mybatisTest.pojo.User" flushCache="false">

 

那么,无论是否执行commit,缓存都不会刷新了。但是这样会造成脏读,只有在特殊情况下才使用

  • 自动刷新

有些情况下,需要设置自动刷新缓存,那么需要配置对应mapper中的cache标签。

flushInterval="10000"

 

该属性表示每隔10秒钟自动刷新一遍缓存

 

原文地址:http://blog.csdn.net/u011403655/article/details/46696065

分享到:
评论

相关推荐

    mybatis一级二级缓存流程图.drawio

    mybatis一级二级缓存流程图.drawio mybatis一级二级缓存流程图.drawio mybatis一级二级缓存流程图.drawio mybatis一级二级缓存流程图.drawio

    深入理解MyBatis中的一级缓存与二级缓存

    "深入理解MyBatis中的一级缓存与二级缓存" MyBatis是一种流行的持久层框架,它提供了缓存机制来提高应用程序的性能。在MyBatis中,有两种类型的缓存:一级缓存和二级缓存。下面我们将深入了解MyBatis中的一级缓存和...

    mybatis一级缓存和二级缓存简单示例

    本文将深入讲解 MyBatis 的一级缓存和二级缓存,并通过一个简单的示例进行说明。 ### 一级缓存 一级缓存是 Session 级别的缓存,也称为本地缓存(Local Cache)。每当我们在一个 SqlSession 中执行了 CRUD 操作,...

    MyBatis缓存(一级缓存、二级缓存)

    缓存是MyBatis性能优化的重要手段,分为一级缓存和二级缓存。在这篇文章中,我们将深入探讨这两个级别的缓存机制及其工作原理。 **一级缓存** 一级缓存是SqlSession级别的缓存,也称为局部缓存。当你执行一个查询...

    mybatis一二级缓存

    在 MyBatis 中,一级缓存和二级缓存是两个重要的性能优化手段,它们可以有效减少对数据库的访问,提高系统的响应速度。下面将详细阐述这两个缓存机制。 ### 一级缓存 一级缓存是 MyBatis 默认开启的本地会话缓存,...

    springMybatis+redis三级缓存框架

    在"springMybatis+redis三级缓存框架"中,MyBatis的二级缓存作为第一级,Redis作为第二级,而Redis中的缓存失效策略(例如LRU,TTL)则可以进一步优化数据的读取。如果一级缓存中未找到所需数据,系统会查询二级缓存...

    mybatis二级缓存学习

    MyBatis二级缓存是MyBatis框架中的一个重要特性,它允许我们在多个SqlSession之间共享数据,从而提高应用性能。本文将深入探讨MyBatis二级缓存的工作原理、配置方式以及如何在实际开发中有效利用。 一、MyBatis二级...

    mybatis二级缓存

    MyBatis一级缓存是SqlSession级别的,而二级缓存则是在整个Mapper配置范围内的全局缓存,可以跨SqlSession共享数据。 在MyBatis中,二级缓存的实现原理如下: 1. 数据读取时,如果命中二级缓存,直接从内存中返回...

    MyBatis3开启二级缓存

    MyBatis的缓存分为一级缓存和二级缓存。一级缓存是SqlSession级别的,同一个SqlSession内的相同SQL语句不会重复执行,而是直接从缓存中获取结果。然而,一级缓存存在生命周期问题,当SqlSession关闭时,一级缓存就会...

    mybatis二级缓存扩展-与redis集成

    在大型系统中,为了提高数据访问效率,MyBatis提供了二级缓存机制。本文将深入探讨如何对MyBatis的二级缓存进行扩展,并将其与Redis集成,以充分利用分布式缓存的优势。 MyBatis的二级缓存是基于全局的,它允许不同...

    从0到1项目搭建-集成 Redis 配置MyBatis二级缓存

    基于 SpringBoot 从0搭建一个企业级开发项目,基于SpringBoot 的项目,并集成MyBatis-Plus、Redis、Druid、Logback ,并使用 Redis 配置 MyBatis 二级缓存。

    Mybatis-plus基于redis实现二级缓存过程解析

    Mybatis-plus基于Redis实现二级缓存过程解析 Mybatis-plus是一款基于Java语言的持久层框架,旨在简化数据库交互操作。然而,在高并发、高性能的应用场景中,数据库的查询操作可能会成为性能瓶颈。为了解决这个问题...

    Mybatis的以及缓存和二级缓存(案例).mhtml

    此文章是对Mybatis框架的一级缓存一级二级缓存的描述,包括他们的作用,案例,以及部分源码分析,对一级缓存以及二级缓存进行了详细的描述以及概括,还有如何使用等内容

    MyBatis 二级缓存 关联刷新实现

     Mybatis提供对缓存的支持,但是在没有配置的默认情况下,它只开启一级缓存,二级缓存需要手动开启。  一级缓存只是相对于同一个SqlSession而言。也就是针对于同一事务,多次执行同一Mapper的相同查询方法,第一...

    深入了解MyBatis二级缓存

    其中,二级缓存是MyBatis中的一种高级缓存机制,它可以将查询结果缓存在内存中,以便下次查询时直接从缓存中获取结果,减少数据库查询次数,提高应用程序的性能。本文将深入了解MyBatis二级缓存,探索其工作原理、...

    分布式系统架构——使用Redis做MyBatis的二级缓存 - CSDN博客1

    分布式系统架构中,使用Redis作为MyBatis的二级缓存是一种常见的优化策略,旨在提高数据访问性能并降低数据库负载。MyBatis是一个流行的Java持久层框架,它允许开发者编写SQL语句并将其与Java代码集成,提供了一种...

    mybatis+redis实现二级缓存

    在本项目中,“mybatis+redis实现二级缓存”是一个巧妙结合了MyBatis持久层框架与Redis内存数据库来优化数据访问速度的实践案例。下面将详细介绍这个项目中的关键技术点以及实现步骤。 首先,MyBatis是一个轻量级的...

    Mybatis一级、二级缓存介绍.zip

    Mybatis一级、二级缓存介绍.zip

    深入了解MyBatis二级缓存共6页.pdf.zip

    其中,二级缓存是MyBatis优化数据库操作的重要特性之一。本文将深入探讨MyBatis的二级缓存机制,旨在帮助开发者更好地理解和利用这一功能。 首先,我们需要了解什么是缓存。缓存是一种存储技术,用于暂时保存经常...

    47-二级缓存 Hibernate-Shiro-MyBatis

    在IT行业中,二级缓存是一种优化数据库访问性能的重要技术,特别是在使用ORM框架(如Hibernate)、权限管理框架(如Shiro)以及SQL映射框架(如MyBatis)时。二级缓存可以存储经常访问的数据,避免频繁地从数据库中...

Global site tag (gtag.js) - Google Analytics