当前位置: 首页 > news >正文

Mybatis一级缓存

一、原生 MyBatis 中

一级缓存作用域:同一个 SqlSession范围内
缓存行为:

1、同一会话中相同查询直接从缓存返回结果
2、执行更新操作(INSERT/UPDATE/DELETE)会清空当前会话缓存
3、会话关闭时缓存自动销毁

二、MyBatis-Spring 中的变化

SqlSessionTemplate的特殊设计,在 MyBatis-Spring 中:

// SqlSessionTemplate 的核心特性
public class SqlSessionTemplate implements SqlSession {// 通过代理实现会话管理private final SqlSession sqlSessionProxy;public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),new Class[] { SqlSession.class },new SqlSessionInterceptor()); // 关键拦截器,重点在于这里SqlSessionInterceptor是一个InvocationHandler,主要在他的Invoke方法。}
}

invoke方法,如果是非事务的情况下,是直接关闭SqlSession。

private class SqlSessionInterceptor implements InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args) {// 获取当前会话(事务内复用)SqlSession session = getSqlSession();try {Object result = method.invoke(session, args);// 非事务环境:立即关闭会话if (!isSqlSessionTransactional(session)) {session.close();}return result;} finally {// 事务结束时由事务管理器关闭}}
}

Mybatis-Spring的增删改查都会自动的去操作sqlSession,因为Invoke已经包装好了,而原生的Mybatis的是事务需要我们手动去操作,我们需要先拿到Session在拿到Mapper来做增删改操作,最后提交事务。

SqlSession session = sqlSessionFactory.openSession();
try {UserMapper mapper = session.getMapper(UserMapper.class);// 执行操作(自动开启事务)mapper.insert(user);  这里去调用MapperProxy的invoke方法。// 需要显式提交session.commit();
} catch (Exception e) {// 显式回滚session.rollback();
} finally {// 显式关闭会话session.close();
}

结论

所以针对原生的Mybatis

无事务操作=》缓存有效
事务内操作 =》缓存有效
会话SqlSession的生命周期=》手动控制
缓存共享范围=》仅限于单个 SqlSession

MyBatis-Spring (SqlSessionTemplate)

无事务操作=》缓存无效(每次操作使用新会话)
事务内操作=》缓存有效(整个事务使用同一会话)
会话SqlSession的生命周期=》由 Spring事务管理器自动管理
缓存共享范围=》扩展至整个事务期间

举个例子:如果是Mybatis-Spring的框架下

情况 1:无事务环境(缓存无效)

// 无事务方法
public User getUser(int id) {// 每次调用都会创建新会话User user1 = userMapper.findById(id); // 第一次查询数据库,因为这里通过代理对象执行操作,SqlSessionInterceptor的invoke在执行完就会自动关闭sqlSession,代理已经包装好了。User user2 = userMapper.findById(id); // 第二次查询数据库(未命中缓存)return user2;
}

原因:

SqlSessionInterceptor 在每次方法调用后都会关闭会话,相当于每次操作都是新的 SqlSession

情况 2:事务环境(缓存有效)

@Transactional
public User getUserInTransaction(int id) {// 整个事务使用同一个会话User user1 = userMapper.findById(id); // 第一次查询数据库User user2 = userMapper.findById(id); // 从一级缓存获取return user2;
}

原因:

事务开始时,SqlSessionInterceptor 创建会话并绑定到当前线程
事务内所有操作复用同一会话
事务结束后关闭会话

情况 3:更新操作清空缓存

@Transactional
public void updateAndQuery() {User user1 = userMapper.findById(1); // 查询数据库userMapper.updateName(1, "Alice");   // 更新操作(清空缓存)User user2 = userMapper.findById(1); // 重新查询数据库
}

一级缓存使用建议

事务粒度控制:
将需要缓存的操作放在同一事务中
避免过大的事务范围

性能敏感操作:

@Transactional(readOnly = true) //表示当前事务是只读事务
public List<User> getActiveUsers() {// 多次查询相同数据可受益于缓存
}

更新后查询:

@Transactional
public void updateUser(User user) {userMapper.update(user); // 清空缓存// 需要最新数据时直接查询User freshUser = userMapper.findById(user.getId());
}

思考:在一个方法内,谁会触发2次,Mapper的相同参数查询,这不是多余的查询吗?

http://www.dtcms.com/a/519793.html

相关文章:

  • Java+OpenCV实现图片切割
  • Linux云计算基础篇(24)-PXE批量安装和Kickstart工具
  • 从零搭建 RAG 智能问答系统 6:Text2SQL 与工作流实现数据库查询
  • 创建Django项目
  • 注册个人网站的方法建设企业网站费用
  • 初识C语言13.自定义类型(联合体与枚举)
  • WebRTC入门指南:实时通信零基础
  • 深圳外贸营销型网站建设引擎搜索网站
  • Django 表单验证详解Form
  • k8s相关学习
  • 【2026计算机毕业设计】基于Django的社区婴幼儿预防接种系统
  • D030知识图谱科研文献论文推荐系统vue+django+Neo4j的知识图谱|论文本文相似度推荐|协同过滤
  • pg库、MySQL库和sqlite3基本操作
  • Android Studio新手开发第三十天
  • 住房建设部官方网站公示公告手机网站内容模块
  • 网站建设 数据库连接网站建设公司软件开
  • 深入理解栈与队列:核心特性与实战应用
  • 如何建一个免费的网站南昌做网站优化哪家好
  • 机器学习概念,算法原理及应用
  • Pytorch常用层总结
  • 【Deepseek OCR】重磅测试,mac环境下的体验【本人已经本地实验成功】
  • 轻量化(Lightweight)概念
  • [人工智能-大模型-58]:模型层技术 - 深度神经网络的本质是一个复杂的复合数学函数
  • 【小白笔记】将十进制数(Decimal)转换为二进制数(Binary),并计算二进制表示中“1”的个数
  • 长春怎么注册网站平台wordpress 视频列表
  • 【ReAcTable】面向表格问答任务的ReAct增强框架
  • Docker 部署 Elasticsearch 全流程手册
  • React 集成Redux数据状态管理 数据共享 全局共享
  • Docker与Nginx:现代Web部署的完美二重奏
  • 【JUnit实战3_08】第四章:从 JUnit 4 迁移到 JUnit 5