Redis--简单的缓存

本文详细介绍了如何在SpringBoot+Mybatis环境中利用Redis实现分布式缓存,通过自定义缓存处理类实现数据的存取,提高系统的响应速度和并发能力。通过配置Redis连接信息,并替换Mybatis默认缓存,实现数据查询时先从Redis中获取,若不存在再从数据库查询并存入Redis。同时,文章还讨论了缓存数据的优化策略,如使用MD5加密减少键的长度。
摘要由CSDN通过智能技术生成

什么是分布式缓存?

在原始的应用中,通常将缓存存储在本地应用程序的 JVM 中,但是随着项目微服务化的趋势,在项目以微服务的方式重构后,缓存应是由单独的服务器进行管理和存储,分布在不同的物理区域进行部署,已达到高可用效果。

Mybatis原始的缓存存储方式

在未使用分布式缓存时,Mybatis 是自带缓存的 mybatis将每次查询到到的结果存放在一个类的 HashMap 属性中,MyBatis 的缓存处理接口为 org.apache.ibatis.cache Cache 操作的缓存的实现类为 org.apache.ibatis.cache.impl PerpetualCache Mybatis 将查询到的数据缓存到 次实现类的 cashe 属性中。

以下为部分源码

public class PerpetualCache implements Cache {

	//缓存id
    private final String id;
    
    //最终存储缓存处
    private final Map<Object, Object> cache = new HashMap();
	

    public PerpetualCache(String id) {
        this.id = id;
    }

	//查询缓存id
    public String getId() {
        return this.id;
    }
	
	//获取缓存大小
    public int getSize() {
        return this.cache.size();
    }

	//将数据加入缓存
    public void putObject(Object key, Object value) {
        this.cache.put(key, value);
    }

	//获取缓存
    public Object getObject(Object key) {
        return this.cache.get(key);
    }

	//此方法mybatis并未实现调用者 属于保留方法
    public Object removeObject(Object key) {
        return this.cache.remove(key);
    }

	//清除缓存
    public void clear() {
        this.cache.clear();
    }
    
    //......未全部展示源码

在这里插入图片描述
步骤:
当请求到来时访问应用中的dao层mybatis解析映射文件中是否添加了<cache/>缓存标签表示开启缓存。在默认缓存实现类 PerpetualCache 中使用 getObject(Object key)方法尝试获取缓存。如果有将返回缓存中的内容,否则将查询数据库,将得到的结果存入缓存并返回给用户。

分布式缓存的实现原理

此次示例的环境是 SpringBoot + Mybatis + Redis 作为分布式缓存的基本环境。使用Mybatis作为缓存的:存储,获取,删除的操作者,使用 Redis 作为缓存的存储者。

在这里插入图片描述

步骤:
当请求到来时访问应用中的dao层mybatis解析映射文件中是否添加了<cache/>缓存标签表示开启缓存。
若开启类缓存将使用 我们指定的实现类 去redis中获取缓存 如果有将返回缓存 若没有将从数据库查询,再将数据存入redis中并返回给用户。

我们的目的是替换掉mybatis 中的缓存默认处理类,让其使用我们提供的实现类来操作缓存 在Redis中。

实现示例

依赖项:

省略Springboot依赖

数据库三件套

	<dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>druid-spring-boot-starter</artifactId>
       </dependency>
       <dependency>
           <groupId>org.mybatis.spring.boot</groupId>
           <artifactId>mybatis-spring-boot-starter</artifactId>
       </dependency>
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
       </dependency>
     <dependency>

使用此依赖操作Redis 数据库

  		<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

步骤

注意将实体类实现序列化接口

  1. 创建普通的 SSM 项目
  2. 配置应用。

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 907282050
    url: jdbc:mysql://127.0.0.1:3306/db_test?serverTimezone=Asia/Shanghai&useSSL=false
    type: com.alibaba.druid.pool.DruidDataSource

# 配置redis连接信息	
  redis:
    host: localhost
    port: 6379
    database: 0

mybatis:
  mapper-locations: classpath:mappers/*.xml
  type-handlers-package: com.ccnn.test_01.com.ccnn.test_01.entity

logging:
  level:
    com.ccnn.test_01.dao: DEBUG

  1. 获取Springboot 容器中注入好的操作redis的 RedisTemplate对象
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
       this.applicationContext = applicationContext;
    }

    public static Object getRedisTemplate(String name){
        return applicationContext.getBean(name);
    }
}

  1. 自定义类实现 org.apache.ibatis.cache.Cache 接口和其中方法
import com.ccnn.test_01.jedis.ApplicationContextUtil;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

public class RedisCache implements Cache {

    /* id 的值为此类的全限定类名(com.ccnn.test_01.dao.UserMapper)和mapper.xml映射文件中的namespace
    标签中的值相同*/
    private final String id;
	
	/* 将 RedisTemplate作为属性 声明方便使用*/
    private final RedisTemplate<Object,Object> redisTemplate;

    public RedisCache(String id) {
        this.id = id;
        /* 获取RedisTemplate对象并设置 序列化规则 */
        redisTemplate = (RedisTemplate<Object,Object> ) ApplicationContextUtil.getRedisTemplate("redisTemplate");
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
    }

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


    /*  从缓存中获取数据

        如果未在缓存中获取到数据  则会从数据库中查询,
        将查询到的数据使用此类的 putObject();向缓存中
        存储(在mybatis使用的默认缓存实现类:org.apache.
        ibatis.cache.impl.PerpetualCache中 使用了一个HashMap 对象
        进行存储)

        因此我们在此处将数据从 Redis 中取出数据作为缓存返回。

     */
    @Override
    public Object getObject(Object o) {
        /*此处 参数 o 和 putObject(Object o, Object o1) 中的 o为同一参数*/
        System.out.println("获取数据——————————"+o)
        return redisTemplate.opsForHash().get(id,o.toString());
    }


    /*  向缓存中存储数据

        在缓存中未查询到结果时 将从数据库中查询,将查询到的结果
        存入到缓存中,因此 在此处将数据存储到 Redis 中。

     */
    @Override
    public void putObject(Object o, Object o1) {
        //以下为参数的输出结果
        /*2057322197:1276118677:com.ccnn.test_01.dao.UserMapper.
        selectUser:0:2147483647:select * from user where name
        = ?:小李:SqlSessionFactoryBean---[User{name='小李', age=15}]*/
        System.out.println(o.toString()+"---"+o1.toString());

        redisTemplate.opsForHash().put(id,o.toString(),o1);
    }

    /*mybatis 并未实现这个发的调用  无调用者*/
    @Override
    public Object removeObject(Object o) {
        return null;
    }

    //移除缓存中的数据
    @Override
    public void clear() {
       redisTemplate.delete(id);
    }

    @Override
    public int getSize() {
        return redisTemplate.opsForHash().size(id).intValue();
    }

	  //加密方法
    private static String getKeyToM5(String k){
        return DigestUtils.md5DigestAsHex(k.getBytes());
    }
}

在 更新 删除 添加 时都会根据 id 属性的值将redis数据库中的值删除,在下次查询时则将值从mysql中添加到redis中。

  1. 为Mapper.xml 映射文件添加 <cache type="自定义实现类"/>
<?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="com.ccnn.test_01.dao.UserMapper">

	<!--指定缓存处理类-->
    <cache type="com.ccnn.test_01.cache.RedisCache"/>

    <select id="selectUser" resultType="com.ccnn.test_01.entity.User" parameterType="String">
        select * from user where name = #{name}
    </select>

    <update id="updateUser" parameterType="String">
        update user set name = #{name} where age = 15
    </update>

</mapper>
  1. 适应多表联查。

在多表联查时 请将两个有关联关系的mapper.xml文件中的一方去共享 主要 的一方的缓存 cache 标签修改为:

  <?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="com.ccnn.test_01.dao.EmpMapper">
		
	<cache-ref namespace="被共享的mapper.xml文件的 命名空间的值"/>	
	
    <select >
       .......
    </select>

   
</mapper>

使双方对一块 redis 中的缓存进行操作,在任意一方对数据进行修改时都会清空此项缓存。

优化

将存入 redis 中的缓存数据进行优化。

在看到打印的缓存数据的 key 时我们发现 key过于长 因此使用 spring 内涵的 MD5 加密工具类(两个内容相同的文件加密后得到的值必定相同)进行加密 生成32位16进制的 字符串 ,作为 key 存入到Redis中。在获取缓存时再进行解密。

上文已添加。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值