首页 > 数据库 >Mybatis 的 SqlSession 和一级缓存为什么失效?

Mybatis 的 SqlSession 和一级缓存为什么失效?

时间:2024-02-05 11:46:46浏览次数:32  
标签:事务 缓存 一级 二级缓存 SqlSession session Mybatis

目录

SqlSession是什么

SqlSession是Mybatis 中定义的,用来表示与关系数据库的一次会话,会话定义了各种具体的操作,查询、数据更新(包含保存、更新、删除)操作。而这些操作都在与数据库建立会话的基础上进行的。SqlSession 可以看作是对Connection 更加高级的抽象,从其方法上更加可以看出他具有更加明显的操作特征。

SqlSession分类

mybatis的SqlSession有三种:DefaultSqlSession、SqlSessionManager、SqlSessionTemplate,前两者是 mybtais 默认情况下使用的,第三种主要用到 mybatis 和 spring 整合的时候。

SqlSession的创建

SqlSessionFactory.openSession() 的方法源码

// org/apache/ibatis/session/defaults/DefaultSqlSessionFactory.java
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
        final Environment environment = configuration.getEnvironment();
        final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
        tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
        final Executor executor = configuration.newExecutor(tx, execType);
        return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
        closeTransaction(tx); // may have fetched a connection so lets call close()
        throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
        ErrorContext.instance().reset();
    }
}

通过源码我们知道每次 SqlSession(准确地说是 DefaultSqlSession )的创建都会有一个 Transaction 事务对象 的生成。也就是说:

  • 一个事务 Transaction 对象与一个 SqlSession 对象是一对一的关系

  • 同一个 SqlSession 不管执行多少次数据库操作,只要没有执行 close,那么,整个操作都是在同一个 Transaction 中执行的

但需要注意的是,我们整合Spring之后用到的其实都是 SqlSessionTemplate ,与这里的 DefaultSqlSession 不是同一个SqlSession对象,不懂的看上面的。

为什么和 Spring 整合后的 SqlSession 一级缓存偶尔会失效

一级缓存和二级缓存

一级缓存是SqlSession级别的缓存,在操作数据库时,每个SqlSession类的实例对象缓存的数据区域(Map)可以用于存储缓存数据,不同的SqlSession类的实例对象缓存的数据区域是互不影响的。一级缓存工作原理图:

image

二级缓存是 Mapper 级别的缓存,多个 SqlSession 实例对象可以共用二级缓存,二级缓存是跨 SqlSession 的。 二级缓存模式图如下:

image

我们都知道一级缓存是 SqlSession 级别的缓存,那么,一级缓存失效,肯定是因为 SqlSession 不一致,那么,我们进入到 getSqlSession 方法中:

// org/mybatis/spring/SqlSessionUtils.java
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    // ...
    // 从ThreadLocal变量里面获取到Spring的事务同步管理器
    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
    // 调用静态方法 sessionHoler 判断是否存在符合要求的sqlSession
    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
      return session;
    }
    // 如果 SqlSessionHolder 中获取的 SqlSession 为空,则新建一个 SqlSession
    session = sessionFactory.openSession(executorType);
    // 判断当前是否存在事务,将sqlSession 绑定到 sqlSessionHolder 中,并放到 threadLoacl 当中
    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    return session;
}

可以看出,Spring 只有在开启了事务之后,在同一个事务里的 SqlSession 会被缓存起来,同一个事务中,多次查询是可以命中缓存的。

总结

  • 同一事务中不管调用多少次 mapper 里的方法 ,最终,都是用的同一个 sqlSession,即一个事务中使用的是同一个sqlSession

  • 同一事务中,Mybatis 的一级缓存才会有效

  • 如果没有开启事务,调用一次 mapper 里的方法将会新建一个sqlSession来执行方法


标签:事务,缓存,一级,二级缓存,SqlSession,session,Mybatis
From: https://www.cnblogs.com/larry1024/p/18007644

相关文章

  • Nginx--缓存
    一般存的是静态资源,可以提高客户端的访问速度,并减轻服务器的压力 1 客户端缓存通过设置expires指令,响应头中将会返回Expires和Cache-Control字段当浏览器发现响应头存在这样的缓存字段,当再次请求相同资源时,就会确认在客户端的资源是否过期location/{expires30m......
  • Java Integer包装类缓存(cache)
    ​ Java的Integer类有一个内部的缓存机制,主要用于优化自动装箱(autoboxing)和拆箱(unboxing)的性能。这个特性首次引入于Java5,旨在减少对频繁使用的小整数值的重复对象创建,从而提高性能和减少内存使用。 参数文档:JavaInteger包装类缓存(cache)-CJavaPy1、缓存范围默认情况下,I......
  • 【MybatisPuls】如何调用DM存储过程并返回多结果集
    一、创建DM存储过程CREATEORREPLACEPROCEDUREyour_procedure(result1OUTCURSOR,result2OUTCURSOR)ASBEGIN--打开第一个结果集OPENresult1FORSELECTtop10*FROM表;--打开第二个结果集OPENresult2FORSELECTtop10*FROM表;END;--SQL测试存储过......
  • redis缓存
    放入缓存中的数据应该指定过期时间,为什么呢, 因为过期时间可以确保缓存中的数据不会永久存在,从而避免缓存中出现过时或无效的数据。指定过期时间有以下几个重要原因:1. 数据更新和一致性:当数据发生变化时,缓存中的数据可能会变得过时。如果不过时,新的数据就更新不了,就失去了缓存......
  • MyBatis整合第三方缓存EHCache
    EHCache缓存针对于MyBatis的二级缓存。MyBatis默认二级缓存是SqlSessionFactory级别的。添加依赖<!--MyBatis-EHCache整合包--><dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</vers......
  • Mybatis
    一、自定义持久层框架1.1分析持久层。与数据交互的一层。Dao层 。可能存在的问题:问题代码解决方案硬编码。对底层驱动和数据库配置信息硬编码Class.forName("com.mysql.jdbc.Driver");connection=DriverManager.getConnection("jdbc:......
  • 解决缓存与数据库同步下的同步锁问题之分段锁
    契子  在实际业务会我们会使用第三方的缓存例如:Reids、Memcache等;但是,并且我们在查询使用缓存时都得尽可能的保证缓存的一致性,在读取时得保证尽可能的保证缓存拿到的是数据库的最新数据,那么在实现的逻辑上一般都为这样:1、请求线程先读取缓存实现2、如果缓存没有数据的话触发......
  • 本地缓存Ehcache的应用实践 | 京东云技术团队
    java本地缓存包含多个框架,其中常用的包括:Caffeine、GuavaCache和Ehcache,其中Caffeine号称本地缓存之王,也是近年来被众多程序员推崇的缓存框架,同时也是SpringBoot内置的本地缓存实现。但是除了Caffeine之外,还有一款也不错的本地缓存框架Ehcache,具有快速、灵活,并支持内存和磁盘缓......
  • mybatis
    一.传参参数类型parameterType推荐不写,除非自定义类型与引用的第三方类型重名,需要特别指定。(1)传递一个参数(基本类型或其包装类型)mapper接口:publicinterfacePersonMapper{//根据员工编号获取员工信息和员工部门publicPersongetPersonById(Integerid);}x......
  • MyBatis动态SQL教程
    动态SQL是MyBatis中非常强大且灵活的功能,允许你根据不同的条件构建SQL查询。这主要通过<if>、<choose>、<when>、<otherwise>、<foreach>等标签实现。查询场景/***根据条件查询员工信息*@paramemp*@return*/List<Emp>getEmpCondition(Empemp);if标签的使用......