MyBatis 二级缓存整合Redis【学习记录】

news2024/11/20 8:25:49

二级缓存整合Redis

上篇文章介绍了MyBatis自带的二级缓存,但是这个缓存是单服务器工作,无法实现分布式缓存。那么什么是分布式缓存呢?假设现在有两个服务器1和2,用户访问的时候访问了服务器1,查询后的缓存就会放在服务器1上,假设现在有个用户访问的是服务器2,那么他在服务器2上就无法获取刚刚的那个缓存,如下如所示:

在这里插入图片描述

为了解决这个问题,就得找一个分布式的缓存,专门用来存储缓存数据的,这样不同的服务器要缓存数据都往它那里存,取缓存数据也从它那里取,如下图所示:

在这里插入图片描述
如上图所示,在几个不同的服务器之间,我们使用第三方缓存框架,将缓存都放在这个第三方框架中,然后无论有多少台服务器,我们都能从缓存中获取数据。

这里我们使用MyBatis与Redis整合。

我们知道,MyBatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。MyBatis本身默认实现了一个,但是这个缓存的实现无法实现分布式缓存,所以我们要自己来实现。Redis分布式缓存就可以,Mybatis提供了一个针对cache接口的Redis实现类,该类存在mybatis-redis包中。

1)pom文件

<dependency>
	<groupId>org.mybatis.caches</groupId>
	<artifactId>mybatis-redis</artifactId>
	<version>1.0.0-beta2</version>
</dependency>

2)mapper.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.mybatisTest.mapper.UserMapper">
	<!-- 二级缓存类地址 -->
	<cache type="org.mybatis.caches.redis.RedisCache"/>
	<select id="findUsers" resultType="com.test.pojo.User" useCache="true">
        SELECT * FROM user
    </select>
</mapper>

3)redis.properties(文件名称不能改,不然无法获取里面的数据)

redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password=
redis.database=0

4)测试

@Test
public void SecondLevelCache(){
	//创建SqlSession1
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);
    //创建SqlSession2
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    lUserMapper mapper2 = sqlSession2.getMapper(lUserMapper.class);
    //创建SqlSession3
    SqlSession sqlSession3 = sqlSessionFactory.openSession();
    lUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);
    
    User user1 = mapper1.findUserById(1);
    //清空⼀级缓存,存入二级缓存
    sqlSession1.close();
    User user = new User();
    user.setId(1);
    user.setUsername("lisi");
    mapper3.updateUser(user);
    sqlSession3.commit();
    User user2 = mapper2.findUserById(1);
    System.out.println(user1==user2);
}

5)源码分析

RedisCache和大家普遍实现Mybatis的缓存方案大同小异,无非是实现Cache接口,并使用Jedis操作缓存,不过该项目在设计细节上有一些区别。

package org.mybatis.caches.redis;

import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public final class RedisCache implements Cache {
    private final ReadWriteLock readWriteLock = new DummyReadWriteLock();
    private String id;
    private static JedisPool pool;

    public RedisCache(String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        } else {
            this.id = id;
            RedisConfig redisConfig = RedisConfigurationBuilder.getInstance().parseConfiguration();
            pool = new JedisPool(
            	redisConfig, redisConfig.getHost(), 
            	redisConfig.getPort(), redisConfig.getConnectionTimeout(), 
            	redisConfig.getSoTimeout(), redisConfig.getPassword(), 
            	redisConfig.getDatabase(), redisConfig.getClientName()
            );
        }
    }
}

RedisCache在MyBatis启动的时候,由MyBatis的CacheBuilder创建,创建的方式很简单,就是调用RedisCache的带有String参数的构造方法,即RedisCache(String id);而在RedisCache的构造方法中,调用了RedisConfiguration来创建RedisConfig对象,并使用RedisConfig来创建JedisPool。

RedisConfig类继承了JedisPoolConfig,并提供了host,port等属性的包装,简单看一下RedisConfig的属性:

public class RedisConfig extends JedisPoolConfig {
    private String host = "localhost";
    private int port = 6379;
    private int connectionTimeout = 2000;
    private int soTimeout = 2000;
    private String password;
    private int database = 0;
    private String clientName;

    public RedisConfig() {
    }
}

RedisConfig对象是由RedisConfigurationBuilder创建的,简单看下这个类的主要方法:

final class RedisConfigurationBuilder {
    private static final RedisConfigurationBuilder INSTANCE = new RedisConfigurationBuilder();
    private static final String SYSTEM_PROPERTY_REDIS_PROPERTIES_FILENAME = "redis.properties.filename";
    private static final String REDIS_RESOURCE = "redis.properties";
    private final String redisPropertiesFilename = System.getProperty("redis.properties.filename", "redis.properties");

    private RedisConfigurationBuilder() {
    }

    public static RedisConfigurationBuilder getInstance() {
        return INSTANCE;
    }

    public RedisConfig parseConfiguration() {
        return this.parseConfiguration(this.getClass().getClassLoader());
    }

    public RedisConfig parseConfiguration(ClassLoader classLoader) {
        Properties config = new Properties();
        InputStream input = classLoader.getResourceAsStream(this.redisPropertiesFilename);
        if (input != null) {
            try {
                config.load(input);
            } catch (IOException var12) {
                throw new RuntimeException("An error occurred while reading classpath property '" + this.redisPropertiesFilename + "', see nested exceptions", var12);
            } finally {
                try {
                    input.close();
                } catch (IOException var11) {
                }
            }
        }
        RedisConfig jedisConfig = new RedisConfig();
        this.setConfigProperties(config, jedisConfig);
        return jedisConfig;
    }

核心方法就是parseConfiguration方法,该方法从classpath中读取一个redis.properties文件:

host=localhost
port=6379
connectionTimeout=5000
soTimeout=5000
password= database=0 clientName=

并将该配置文件中内容设置到RedisConfig对象中,并返回;接下来,就是RedisCache使用RedisConfig类创建完成jedisPool;在RedisCache中实现了一个简单的模板方法,来操作Redis;

public final class RedisCache implements Cache {
   
    private Object execute(RedisCallback callback) {
        Jedis jedis = pool.getResource();

        Object var3;
        try {
            var3 = callback.doWithRedis(jedis);
        } finally {
            jedis.close();
        }

        return var3;
    }

    public String getId() {
        return this.id;
    }
}

模板接口为RedisCallback,这个接口中就只需要实现一个doWithRedis方法而已;

public interface RedisCallback {
    Object doWithRedis(Jedis jedis);
}

接下来看看Cache中最重要的两个方法:putObject和getObject,通过这两个方法来查看mybatis-redis储存数据的格式:

public final class RedisCache implements Cache {
	 @Override
     public void putObject(final Object key, final Object value) {
         execute(new RedisCallback() {
             @Override
             public Object doWithRedis(Jedis jedis) {
                 jedis.hset(id.toString().getBytes(), key.toString().getBytes(),
                         SerializeUtil.serialize(value));
                 return null;
             }
         });
     }
     @Override
     public Object getObject(final Object key) {
         return execute(new RedisCallback() {
             @Override
             public Object doWithRedis(Jedis jedis) {
                 return SerializeUtil.unserialize(jedis.hget(id.toString().getBytes(),
                         key.toString().getBytes()));
             }
         });
     }
}

可以很清楚的看到,mybatis-redis在存储数据的时候,是使用的hash结构,把cache的id作为这个hash的key(cache的id在mybatis中就是mapper的namespace);这个mapper中的查询缓存数据作为hash的field,需要缓存的内容直接使用SerializeUtil存储,SerializeUtil和其它的序列化类差不多,负责对象的序列化和反序列化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/194495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

酒店预订订单的分析与建模【决策树、xgboost】

酒店预订订单的分析与建模【决策树、xgboost】 本项目包含 1.数据处理 2.数据探索性分析 3.网格搜索对决策树、xgboost进行模型参数调优 4.基于五折交叉验证的决策树、xgboost模型预测 专栏和往期项目 &#x1f449;往期文章可以关注我的专栏 下巴同学的数据加油小站 会不…

《神经网络与深度学习》 邱希鹏 学习笔记(二)

正则化 所有损害优化的方法都是正则化。增加优化约束&#xff0c;干扰优化过程 优化约束包括 L1/L2约束&#xff0c;数据增强 干扰优化包括 随机梯度下降 权重衰减 提前停止 在上式中 y(n)为样本n&#xff0c;其展开形式为y^{(n)}为样本n&#xff0c;其展开形式为y(n)为样本…

【Axure教程】低代码可视化编辑器

低代码是一组数字技术工具平台&#xff0c;基于图形化拖拽、参数化配置等更为高效的方式&#xff0c;通过少量代码或不用代码实现数字化转型中的场景应用创新。例如在业务系统中&#xff0c;如果企业新增了一项业务&#xff0c;以往往往需要对系统继续开发和升级&#xff0c;但…

【Python学习笔记】9. Python3 解释器

前言 Linux/Unix的系统上&#xff0c;一般默认的 python 版本为 2.x&#xff0c;我们可以将 python3.x 安装在 /usr/local/python3 目录中。 Python3 解释器 Linux/Unix的系统上&#xff0c;一般默认的 python 版本为 2.x&#xff0c;我们可以将 python3.x 安装在 /usr/loca…

IDEA 常用插件跟配置提升开发效率

工欲善其事必先利其器 安装好 IntelliJ IDEA 后&#xff0c;进行如下的初始化操作&#xff0c;工作效率提升50倍。 一、插件 1. Codota 代码智能提示插件 只要打出首字母就能联想出一整条语句&#xff0c;这也太智能了&#xff0c;还显示了每条语句使用频率。原因是它学习了…

最全的视频转换器工具清单,这18款免费视频格式转换器记得收藏

审查和比较具有功能和定价的最佳视频转换器软件。从这个顶级付费和免费在线视频转换器工具列表中选择&#xff0c;以快速轻松地转换任何视频&#xff1a; 什么是视频转换器&#xff1f; 视频转换工具允许您将视频从一种格式转换为另一种格式。第一个商业上成功的视频格式是 Q…

11.1-股票基金历年收益率计算

文章目录1. 计算目标2. 关键问题3. 获取交易日历4. 逻辑编写1. 计算目标 我们想知道&#xff0c;一只股票标的&#xff0c;在之前的几年中&#xff0c;每一年的年化收益率是多少&#xff1f; 如果将每年的年化收益率进行求和汇总&#xff0c;截止到今年&#xff0c;总共年化收…

五、Mybatis详细教程

Mybatis概述 1 Mybatis概念 MyBatis 是一款优秀的持久层框架&#xff0c;用于简化 JDBC 开发 MyBatis 本是 Apache 的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code&#xff0c;并且改名为MyBatis 。2013年11月迁移到Github 官网&am…

Qt OpenGL(三十五)——Qt OpenGL 核心模式-点云(斯坦福兔子)

提示:本系列文章的索引目录在下面文章的链接里(点击下面可以跳转查看): Qt OpenGL 核心模式版本文章目录 Qt OpenGL(三十五)——Qt OpenGL 核心模式-点云(斯坦福兔子) 一、场景 我们在平时的项目中,有的时候会遇到,激光雷达等这些设置采集的数据集,不管是在机器人、…

【微服务】分布式缓存Redis

分布式缓存Redis基于Redis集群解决单机Redis存在的问题1.Redis持久化1.1.RDB持久化1.1.1.执行时机1.1.2.RDB原理1.1.3.小结1.2.AOF持久化1.2.1.AOF原理1.2.2.AOF配置1.2.3.AOF文件重写1.3.RDB与AOF对比2.Redis主从2.1.搭建主从架构2.2.主从数据同步原理2.2.1.全量同步2.2.2.增量…

UVM实战(张强)--- UART实例代码详细注解

目录一、整体的设计结构图二、各个组件代码详解2.1 DUT2.2 my_driver2.3 my_transaction2.4 my_env2.5 my_monitor2.6 my_agent2.7 my_model2.8 my_scoreboard2.9 my_sequencer2.10 base_test2.11 my_case02.12 my_case1一、整体的设计结构图 各个模块的基础介绍&#xff1a; &…

Spring核心——面向切面编程(AOP)

Spring核心——AOP&#xff08;Aspect-oriented programming&#xff09;一、概念二、作用三、AOP核心概念1.连接点&#xff08;JoinPoint&#xff09;2.切入点&#xff08;Pointcut&#xff09;3.通知&#xff08;Advice&#xff09;4.通知类5.切面&#xff08;Aspect&#xf…

c语言 结构体 动态内存 动态内存管理 模拟实现atoi 找单身狗 文件操作程序编译和链接 预处理 交换奇偶位 offsetof宏的实现 习题

结构体大小 【题目名称】 在32位系统环境&#xff0c;编译选项为4字节对齐&#xff0c;那么sizeof(A)和sizeof(B)是&#xff08; C &#xff09; 对齐数是取其较小值 struct A {int a;short b;int c;char d; }; struct B {int a;short b;char c;int d; };【题目内容】 A. 1…

小程序项目学习--第五章:项目实战一

第五章&#xff1a;项目实战一、 01_(了解)音乐小程序的项目介绍 坑关于Vant Weapp中组件引入未找到的解决方案 [ pages/main-music/main-music.json 文件内容错误] pages/main-music/main-music.json: [“usingComponents”][“van-search”]: “vant/weapp/search/index”…

阿里云们扎堆集结,数据库黄金时代到了?

配图来自Canva可画 作为全球数一数二的信息产业大国&#xff0c;我国在信息技术软硬件底层标准、架构、产品以及生态体系方面&#xff0c;长期被外商“卡脖子”&#xff0c;其中数据库市场更是长期被甲骨文等外商公司所占据。 近年来伴随着信创产业的高速发展&#xff0c;国内…

第七章 idea集成git本地库操作

第一节 配置忽略文件 1、哪些文件需要忽略&#xff1f; 对于git来说可以忽略的文件 Eclipse工程特定文件 IDEA工IDEA工程特定文件 编译产生的二进制文件&#xff08;对于Maven工程来说就是target目录&#xff09; 2、为什么要忽略这些文件&#xff1f; 与项目的实际功能无…

巧用Golang泛型,简化代码编写

作者 | 百度小程序团队 导读 本文整理了很多的泛型应用技巧&#xff0c;结合具体的实际代码示例&#xff0c;特别是很多直接对Go语言内置的类库的实现进行改造&#xff0c;再通过两者在使用上直观对比&#xff0c;帮助大家对泛型使用思考上提供了更多思路&#xff0c;定会帮助大…

【教程】Python:IDLE开发环境安装与配置保姆级教学

【教程】Python&#xff1a;IDLE开发环境安装与配置保姆级教学下载地址安装步骤编写你的Python程序IDLE交互界面&#xff08;交互式运行&#xff09;IDLE编辑器&#xff08;文件式运行&#xff09;下载地址 请访问官网&#xff1a;python解释器安装 安装步骤 若安装最新版本…

FPGA的ADC信号采集ADS52J90-JESD204B接口

jesd204b实战操作笔记 本篇的内容是基于博主设计的jesd204b接口的ADC和FPGA的硬件板卡&#xff0c;通过调用jesd204b ip核来一步步在FPGA内部实现高速ADC数据采集&#xff0c;jesd204b协议和xilinx 的jesd204 IP核相关基本知识已在前面多篇文章中详细介绍&#xff0c;这里不再…

设计师们都在用的5款有限元分析软件推荐

最好的有限元分析软件可以让您测试物体如何受到外部因素的影响。例如&#xff0c;一家公司可以使用 FEA 软件来测试更新后的产品&#xff0c;看看它是否受到振动、热量和其他因素的影响。前 5 名有限元分析软件ANSYS - 具有基于任务的界面OpenFOAM - 可选择插值SimScale - 在线…