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

手写MyBatis第79弹:MyBatis二级缓存事务一致性:解决脏读与缓存一致性难题

  1. MyBatis二级缓存完整集成:CachingExecutor与TransactionalCacheManager源码级实现

  2. 手写MyBatis二级缓存事务集成:解决脏读与缓存一致性难题

  3. 二级缓存与执行器深度整合:从Mapper配置到事务管理的完整链路

  4. CachingExecutor设计精髓:如何实现事务安全的二级缓存

  5. MyBatis二级缓存事务一致性:TransactionalCacheManager机制详解

目录

正文

一、二级缓存集成的架构全景

二、Mapper配置与缓存实例创建

1. Mapper XML配置解析

2. Configuration中的缓存构建

三、CachingExecutor:二级缓存的执行入口

1. 装饰器模式的应用

2. 更新操作的缓存清理

四、TransactionalCacheManager:事务一致性核心

1. 事务性缓存的必要性

2. 核心实现机制

3. TransactionalCache的事务控制

五、SqlSessionFactory的集成改造

1. Executor创建逻辑

2. MappedStatement缓存配置关联

六、二级缓存的生命周期与失效策略

1. 缓存生命周期管理

2. 基于命名空间的缓存失效

七、事务边界与缓存一致性保障

1. SqlSession事务管理集成

2. 跨命名空间缓存清理

八、生产环境配置建议

1. 缓存配置策略

2. 监控与调优

九、总结


  🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论

🔥🔥🔥(源码 + 调试运行 + 问题答疑)

🔥🔥🔥  有兴趣可以联系我。文末有免费源码

免费获取源码。

更多内容敬请期待。如有需要可以联系作者免费送

更多源码定制,项目修改,项目二开可以联系作者
点击可以进行搜索(每人免费送一套代码):千套源码目录(点我)

2025元旦源码免费送(点我)

我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。


    正文

    一、二级缓存集成的架构全景

    二级缓存的核心挑战在于如何与MyBatis现有的执行流程无缝集成,同时保证事务一致性。这需要设计一个精巧的架构,将缓存逻辑嵌入到SQL执行的生命周期中。

    集成核心组件关系

    • CachingExecutor:作为执行器的装饰器,拦截所有数据库操作

    • TransactionalCacheManager:管理事务期间的缓存状态

    • MappedStatement:承载缓存的配置信息

    • SqlSession:根据配置决定是否启用缓存执行器

    二、Mapper配置与缓存实例创建

    1. Mapper XML配置解析
     <!-- UserMapper.xml --><mapper namespace="com.example.UserMapper"><cache eviction="LRU"flushInterval="60000"size="1000"readOnly="true"/><select id="selectById" parameterType="long" resultType="User" useCache="true">SELECT * FROM user WHERE id = #{id}</select></mapper>

    配置参数详解:

    • eviction:淘汰策略(LRU、FIFO等)

    • flushInterval:自动刷新间隔(毫秒)

    • size:缓存最大容量

    • readOnly:是否只读(性能与安全权衡)

    2. Configuration中的缓存构建
     public class Configuration {private final Map<String, Cache> caches = new HashMap<>();public void addCache(String namespace, Cache cache) {caches.put(namespace, cache);}public Cache getCache(String namespace) {return caches.get(namespace);}// 解析cache配置并创建Cache实例public Cache buildCache(String namespace, Properties properties) {String eviction = properties.getProperty("eviction", "LRU");int size = Integer.parseInt(properties.getProperty("size", "1024"));boolean readOnly = Boolean.parseBoolean(properties.getProperty("readOnly", "false"));Cache cache = new PerpetualCache(namespace);// 应用装饰器链if ("LRU".equals(eviction)) {cache = new LruCache(cache, size);}if (!readOnly) {cache = new SerializedCache(cache);}cache = new SynchronizedCache(cache);cache = new LoggingCache(cache);addCache(namespace, cache);return cache;}}

    三、CachingExecutor:二级缓存的执行入口

    1. 装饰器模式的应用
     public class CachingExecutor implements Executor {private final Executor delegate;private final TransactionalCacheManager tcm = new TransactionalCacheManager();public CachingExecutor(Executor delegate) {this.delegate = delegate;}@Overridepublic <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,CacheKey key, BoundSql boundSql) throws SQLException {// 检查是否启用二级缓存Cache cache = ms.getCache();if (cache != null && ms.isUseCache() && resultHandler == null) {// 尝试从二级缓存获取List<E> list = (List<E>) tcm.getObject(cache, key);if (list != null) {// 缓存命中return list;}// 缓存未命中,查询数据库list = delegate.query(ms, parameter, rowBounds, resultHandler, key, boundSql);// 将结果放入缓存(事务提交后生效)tcm.putObject(cache, key, list);return list;}// 未启用缓存,直接委托给底层执行器return delegate.query(ms, parameter, rowBounds, resultHandler, key, boundSql);}}
    2. 更新操作的缓存清理
     @Overridepublic int update(MappedStatement ms, Object parameter) throws SQLException {// 执行更新前清理缓存if (ms.getCache() != null) {// 根据配置决定立即清理还是事务提交时清理if (ms.isFlushCacheRequired()) {tcm.clear(ms.getCache());}}// 委托给底层执行器执行更新return delegate.update(ms, parameter);}

    四、TransactionalCacheManager:事务一致性核心

    1. 事务性缓存的必要性

    问题场景

    1. 事务A查询数据(放入缓存但未提交)

    2. 事务B读取缓存(读到未提交的数据)

    3. 事务A回滚(缓存中留下脏数据)

    TransactionalCacheManager通过延迟提交机制解决这个问题。

    2. 核心实现机制
    public class TransactionalCacheManager {private final Map<Cache, TransactionalCache> transactionalCaches = new HashMap<>();public Object getObject(Cache cache, CacheKey key) {return getTransactionalCache(cache).getObject(key);}public void putObject(Cache cache, CacheKey key, Object value) {getTransactionalCache(cache).putObject(key, value);}public void clear(Cache cache) {getTransactionalCache(cache).clear();}public void commit() {for (TransactionalCache txCache : transactionalCaches.values()) {txCache.commit();}}public void rollback() {for (TransactionalCache txCache : transactionalCaches.values()) {txCache.rollback();}}private TransactionalCache getTransactionalCache(Cache cache) {return transactionalCaches.computeIfAbsent(cache, TransactionalCache::new);}}
    3. TransactionalCache的事务控制
     public class TransactionalCache implements Cache {private final Cache delegate;private final Map<Object, Object> entriesToAddOnCommit = new HashMap<>();private final Set<Object> entriesToRemoveOnCommit = new HashSet<>();private boolean clearOnCommit = false;public TransactionalCache(Cache delegate) {this.delegate = delegate;}@Overridepublic Object getObject(Object key) {// 事务期间只从底层缓存读取已提交的数据return delegate.getObject(key);}@Overridepublic void putObject(Object key, Object value) {// 暂存到待提交映射,事务提交后才真正放入缓存entriesToAddOnCommit.put(key, value);}@Overridepublic void clear() {clearOnCommit = true;entriesToAddOnCommit.clear();}public void commit() {if (clearOnCommit) {delegate.clear();}// 移除待删除的条目for (Object key : entriesToRemoveOnCommit) {delegate.removeObject(key);}// 添加待提交的条目for (Map.Entry<Object, Object> entry : entriesToAddOnCommit.entrySet()) {delegate.putObject(entry.getKey(), entry.getValue());}reset();}public void rollback() {reset();}private void reset() {clearOnCommit = false;entriesToAddOnCommit.clear();entriesToRemoveOnCommit.clear();}}

    五、SqlSessionFactory的集成改造

    1. Executor创建逻辑
     public class DefaultSqlSessionFactory implements SqlSessionFactory {@Overridepublic SqlSession openSession() {return openSessionFromDataSource(null, false);}private SqlSession openSessionFromDataSource(TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = getTransaction(level, autoCommit);Executor executor = createExecutor(tx);return new DefaultSqlSession(executor);}private Executor createExecutor(Transaction tx) {Executor executor = new SimpleExecutor(tx);// 如果配置了缓存,包装成CachingExecutorif (configuration.isCacheEnabled()) {executor = new CachingExecutor(executor);}return executor;}}
    2. MappedStatement缓存配置关联
     public class MappedStatement {private String id;private Cache cache;private boolean useCache;private boolean flushCacheRequired;public boolean isUseCache() {return useCache && cache != null;}// Builder模式创建MappedStatementpublic static class Builder {public MappedStatement build() {// 关联对应的Cache实例if (cacheRef != null) {mappedStatement.cache = configuration.getCache(cacheRef);}return mappedStatement;}}}

    六、二级缓存的生命周期与失效策略

    1. 缓存生命周期管理
    public class CacheLifecycleManager {private final ScheduledExecutorService scheduler;private final Map<Cache, ScheduledFuture> flushTasks = new HashMap<>();public void scheduleFlush(Cache cache, long flushInterval) {ScheduledFuture future = scheduler.scheduleAtFixedRate(() -> {cache.clear();}, flushInterval, flushInterval, TimeUnit.MILLISECONDS);flushTasks.put(cache, future);}public void stopFlush(Cache cache) {ScheduledFuture future = flushTasks.remove(cache);if (future != null) {future.cancel(false);}}
    }
    2. 基于命名空间的缓存失效
    public class NamespaceCacheManager {private final Configuration configuration;public void clearNamespaceCache(String namespace) {Cache cache = configuration.getCache(namespace);if (cache != null) {cache.clear();}}// 根据表名清理相关命名空间的缓存public void clearCachesByTable(String tableName) {for (String namespace : getNamespacesByTable(tableName)) {clearNamespaceCache(namespace);}}
    }

    七、事务边界与缓存一致性保障

    1. SqlSession事务管理集成
    public class DefaultSqlSession implements SqlSession {private final Executor executor;@Overridepublic void commit() {try {executor.commit(true);// 提交事务性缓存if (executor instanceof CachingExecutor) {((CachingExecutor) executor).getTransactionalCacheManager().commit();}} catch (SQLException e) {throw new RuntimeException("提交失败", e);}}@Overridepublic void rollback() {try {executor.rollback(true);// 回滚事务性缓存if (executor instanceof CachingExecutor) {((CachingExecutor) executor).getTransactionalCacheManager().rollback();}} catch (SQLException e) {throw new RuntimeException("回滚失败", e);}}
    }
    2. 跨命名空间缓存清理

    复杂业务场景下,一个更新操作可能影响多个Mapper的缓存:

    public class CrossNamespaceCacheCleaner {private final Configuration configuration;public void onUpdate(String statementId, Object parameter) {String updatedNamespace = getNamespaceFromStatementId(statementId);Set<String> affectedNamespaces = analyzeAffectedNamespaces(updatedNamespace, parameter);for (String namespace : affectedNamespaces) {Cache cache = configuration.getCache(namespace);if (cache != null) {cache.clear();}}}
    }

    八、生产环境配置建议

    1. 缓存配置策略
    <!-- 读多写少的场景 -->
    <cache eviction="LRU" size="5000" readOnly="true"/><!-- 读写均衡的场景 -->
    <cache eviction="FIFO" size="1000" flushInterval="300000" readOnly="false"/><!-- 写多读少的场景 -->
    <cache eviction="WEAK" size="500" readOnly="false"/>
    2. 监控与调优
     public class CacheMonitor {public void monitorCachePerformance() {for (Map.Entry<String, Cache> entry : configuration.getCaches().entrySet()) {if (entry.getValue() instanceof LoggingCache) {LoggingCache loggingCache = (LoggingCache) entry.getValue();double hitRatio = loggingCache.getHitRatio();if (hitRatio < 0.3) {// 命中率过低,考虑调整缓存策略logger.warn("缓存 {} 命中率过低: {}", entry.getKey(), hitRatio);}}}}}

    九、总结

    二级缓存的完整集成是一个系统工程,需要精心设计各个组件之间的协作关系。CachingExecutorTransactionalCacheManager是实现事务安全缓存的核心机制。

    关键设计要点

    1. 装饰器模式实现执行器增强

    2. 事务性缓存确保数据一致性

    3. 灵活的配置机制支持不同场景

    4. 完善的生命周期管理避免内存泄漏

    5. 监控体系保障系统稳定运行

    通过本文的完整实现方案,读者可以深入理解MyBatis二级缓存的工作原理,并能够在实际项目中正确配置和使用二级缓存。


    🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞

    💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论

    🔥🔥🔥(源码 + 调试运行 + 问题答疑)

    🔥🔥🔥  有兴趣可以联系我。文末有免费源码

    💖学习知识需费心,
    📕整理归纳更费神。
    🎉源码免费人人喜,
    🔥码农福利等你领!

    💖常来我家多看看,
    📕网址:扣棣编程
    🎉感谢支持常陪伴,
    🔥点赞关注别忘记!

    💖山高路远坑又深,
    📕大军纵横任驰奔,
    🎉谁敢横刀立马行?
    🔥唯有点赞+关注成!

    往期文章推荐:

    基于Springboot + vue实现的学生宿舍信息管理系统
    免费获取宠物商城源码--SpringBoot+Vue宠物商城网站系统 
    【2025小年源码免费送】

    ⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇点击此处获取源码⬇⬇⬇⬇⬇⬇⬇⬇⬇

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

    相关文章:

  1. TENGJUN-4极反向沉板耳机插座:JA05-BPD011-A;技术解析
  2. Raft 算法深度解析:角色、选举、日志复制与分区处理优化
  3. Linux进程(3)
  4. 大型建设网站自己动手制作网站
  5. 濮阳做公司网站青羊区城乡建设网站
  6. 版式设计模板网站wordpress 获取文章
  7. 操作系统页面置换算法FIFO——Belady异常与一个简单案例
  8. 网站开发定制方案企业网店推广运营策略
  9. 杭州设计企业网站高端公司游戏网站开发试验报告
  10. React Native:使用vite创建react项目并熟悉react语法
  11. LazyLLM 学习
  12. 服饰 公司 网站建设新会网页制作公司
  13. 做网站开发的营业执照电商货源网站大全
  14. Redis 主从同步:原理、配置与实战优化
  15. 什么是网站反链企业建设网站风险
  16. 毕业设计开题报告网站开发深圳哪家网站设计比较好
  17. 常用的Python项目管理工具
  18. 网站建设设计技术方案模板linux 下启动 wordpress
  19. 温建设文件发布在哪个网站做网站需要ui设计吗
  20. 数字孪生背后的通信协议:MQTT、OPC UA选型指南
  21. Nest 身份鉴权与权限控制
  22. C#系统日志
  23. CMakeLists.txt语法(三)
  24. 简单flash个人网站山东省建设教育集团网站首页
  25. windows多显示器,独立的虚拟桌面
  26. 国外的app设计网站企管宝官网
  27. 深入解析 Redis 的两种持久化机制:RDB 与 AOF
  28. 爱佳倍 北京网站软件外包公司是什么意思
  29. SCNet平台—让AI更简单、更高效、更实用
  30. 高流量网站设计菏泽网站开发公司