千家信息网

Redis整合Spring及结合使用缓存的示例分析

发表于:2025-01-26 作者:千家信息网编辑
千家信息网最后更新 2025年01月26日,Redis整合Spring及结合使用缓存的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、Redis介绍什么是
千家信息网最后更新 2025年01月26日Redis整合Spring及结合使用缓存的示例分析

Redis整合Spring及结合使用缓存的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

一、Redis介绍

什么是Redis?

redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、 list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原 子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的 把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

它有什么特点?

(1)Redis数据库完全在内存中,使用磁盘仅用于持久性。
(2)相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。
(3)Redis可以将数据复制到任意数量的从服务器。

Redis 优势?

(1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。
(2)支持丰富的数据类型:Redis支持***多数开发人员已经知道像列表,集合,有序集合,散列数据类型。这使得它非常容易解决各种各样的问题,因为我们知道哪些问题是可以处理通过它的数据类型更好。
(3)操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。
(4)多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页***计数等。

Redis 缺点?

(1)单线程

(2)耗内存

二、使用实例

本文使用maven+eclipse+sping

1、引入jar包

       org.springframework.data  spring-data-redis  1.6.1.RELEASE    redis.clients  jedis  2.7.3     

2、配置bean

在application.xml加入如下配置

                                                                                                                                                                                                                                                                

其中配置文件redis一些配置数据redis.properties如下:

#redis中心 redis.host=10.75.202.11 redis.port=6379 redis.password=123456 redis.maxIdle=100 redis.maxActive=300 redis.maxWait=1000 redis.testOnBorrow=true redis.timeout=100000  # 不需要加入缓存的类 targetNames=xxxRecordManager,xxxSetRecordManager,xxxStatisticsIdentificationManager # 不需要缓存的方法 methodNames=  #设置缓存失效时间 com.service.impl.xxxRecordManager= 60 com.service.impl.xxxSetRecordManager= 60 defaultCacheExpireTime=3600  fep.local.cache.capacity =10000

要扫这些properties文件,在application.xml加入如下配置

                              classpath:properties/*.properties                            

3、一些工具类

(1)RedisUtil

上面的bean中,RedisUtil是用来缓存和去除数据的实例

package com.mucfc.msm.common;  import java.io.Serializable; import java.util.Set; import java.util.concurrent.TimeUnit;  import org.apache.log4j.Logger; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations;  /** * redis cache 工具类 * */ public final class RedisUtil { private Logger logger = Logger.getLogger(RedisUtil.class); private RedisTemplate redisTemplate;  /**   * 批量删除对应的value   *   * @param keys   */ public void remove(final String... keys) {   for (String key : keys) {    remove(key);   } }  /**   * 批量删除key   *   * @param pattern   */ public void removePattern(final String pattern) {   Set keys = redisTemplate.keys(pattern);   if (keys.size() > 0)    redisTemplate.delete(keys); }  /**   * 删除对应的value   *   * @param key   */ public void remove(final String key) {   if (exists(key)) {    redisTemplate.delete(key);   } }  /**   * 判断缓存中是否有对应的value   *   * @param key   * @return   */ public boolean exists(final String key) {   return redisTemplate.hasKey(key); }  /**   * 读取缓存   *   * @param key   * @return   */ public Object get(final String key) {   Object result = null;   ValueOperations operations = redisTemplate     .opsForValue();   result = operations.get(key);   return result; }  /**   * 写入缓存   *   * @param key   * @param value   * @return   */ public boolean set(final String key, Object value) {   boolean result = false;   try {    ValueOperations operations = redisTemplate      .opsForValue();    operations.set(key, value);    result = true;   } catch (Exception e) {    e.printStackTrace();   }   return result; }  /**   * 写入缓存   *   * @param key   * @param value   * @return   */ public boolean set(final String key, Object value, Long expireTime) {   boolean result = false;   try {    ValueOperations operations = redisTemplate      .opsForValue();    operations.set(key, value);    redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);    result = true;   } catch (Exception e) {    e.printStackTrace();   }   return result; }  public void setRedisTemplate(    RedisTemplate redisTemplate) {   this.redisTemplate = redisTemplate; } }

(2)MethodCacheInterceptor

切面MethodCacheInterceptor,这是用来给不同的方法来加入判断如果缓存存在数据,从缓存取数据。否则***次从数据库取,并将结果保存到缓存 中去。

package com.mucfc.msm.common;  import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties;  import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.apache.log4j.Logger;  public class MethodCacheInterceptor implements MethodInterceptor { private Logger logger = Logger.getLogger(MethodCacheInterceptor.class); private RedisUtil redisUtil; private List targetNamesList; // 不加入缓存的service名称 private List methodNamesList; // 不加入缓存的方法名称 private Long defaultCacheExpireTime; // 缓存默认的过期时间 private Long xxxRecordManagerTime; // private Long xxxSetRecordManagerTime; //  /**   * 初始化读取不需要加入缓存的类名和方法名称   */ public MethodCacheInterceptor() {   try {     File f = new File("D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");     //配置文件位置直接被写死,有需要自己修改下        InputStream in = new FileInputStream(f); //   InputStream in = getClass().getClassLoader().getResourceAsStream( //     "D:\\lunaJee-workspace\\msm\\msm_core\\src\\main\\java\\com\\mucfc\\msm\\common\\cacheConf.properties");    Properties p = new Properties();    p.load(in);    // 分割字符串    String[] targetNames = p.getProperty("targetNames").split(",");    String[] methodNames = p.getProperty("methodNames").split(",");     // 加载过期时间设置    defaultCacheExpireTime = Long.valueOf(p.getProperty("defaultCacheExpireTime"));    xxxRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxRecordManager"));    xxxSetRecordManagerTime = Long.valueOf(p.getProperty("com.service.impl.xxxSetRecordManager"));    // 创建list    targetNamesList = new ArrayList(targetNames.length);    methodNamesList = new ArrayList(methodNames.length);    Integer maxLen = targetNames.length > methodNames.length ? targetNames.length      : methodNames.length;    // 将不需要缓存的类名和方法名添加到list中    for (int i = 0; i < maxLen; i++) {     if (i < targetNames.length) {      targetNamesList.add(targetNames[i]);     }     if (i < methodNames.length) {      methodNamesList.add(methodNames[i]);     }    }   } catch (Exception e) {    e.printStackTrace();   } }  @Override public Object invoke(MethodInvocation invocation) throws Throwable {   Object value = null;    String targetName = invocation.getThis().getClass().getName();   String methodName = invocation.getMethod().getName();   // 不需要缓存的内容   //if (!isAddCache(StringUtil.subStrForLastDot(targetName), methodName)) {   if (!isAddCache(targetName, methodName)) {    // 执行方法返回结果    return invocation.proceed();   }   Object[] arguments = invocation.getArguments();   String key = getCacheKey(targetName, methodName, arguments);   System.out.println(key);    try {    // 判断是否有缓存    if (redisUtil.exists(key)) {     return redisUtil.get(key);    }    // 写入缓存    value = invocation.proceed();    if (value != null) {     final String tkey = key;     final Object tvalue = value;     new Thread(new Runnable() {      @Override      public void run() {       if (tkey.startsWith("com.service.impl.xxxRecordManager")) {        redisUtil.set(tkey, tvalue, xxxRecordManagerTime);       } else if (tkey.startsWith("com.service.impl.xxxSetRecordManager")) {        redisUtil.set(tkey, tvalue, xxxSetRecordManagerTime);       } else {        redisUtil.set(tkey, tvalue, defaultCacheExpireTime);       }      }     }).start();    }   } catch (Exception e) {    e.printStackTrace();    if (value == null) {     return invocation.proceed();    }   }   return value; }  /**   * 是否加入缓存   *   * @return   */ private boolean isAddCache(String targetName, String methodName) {   boolean flag = true;   if (targetNamesList.contains(targetName)     || methodNamesList.contains(methodName)) {    flag = false;   }   return flag; }  /**   * 创建缓存key   *   * @param targetName   * @param methodName   * @param arguments   */ private String getCacheKey(String targetName, String methodName,    Object[] arguments) {   StringBuffer sbu = new StringBuffer();   sbu.append(targetName).append("_").append(methodName);   if ((arguments != null) && (arguments.length != 0)) {    for (int i = 0; i < arguments.length; i++) {     sbu.append("_").append(arguments[i]);    }   }   return sbu.toString(); }  public void setRedisUtil(RedisUtil redisUtil) {   this.redisUtil = redisUtil; } }

4、配置需要缓存的类或方法

在application.xml加入如下配置,有多个类或方法可以配置多个

                                                                      com\.mucfc\.msm\.service\.impl\...*ServiceImpl.*                   

5、执行结果:

写了一个简单的单元测试如下:

@Test  public void getSettUnitBySettUnitIdTest() {      String systemId = "CES";      String merchantId = "133";      SettUnit configSettUnit = settUnitService.getSettUnitBySettUnitId(systemId, merchantId, "ESP");      SettUnit configSettUnit1 = settUnitService.getSettUnitBySettUnitId(systemId, merchantId, "ESP");      boolean flag= (configSettUnit == configSettUnit1);      System.out.println(configSettUnit);      logger.info("查找结果" + configSettUnit.getBusinessType());     //  localSecondFIFOCache.put("configSettUnit", configSettUnit.getBusinessType());   //  String string = localSecondFIFOCache.get("configSettUnit");        logger.info("查找结果" + string);  }

这是***次执行单元测试的过程:

MethodCacheInterceptor这个类中打了断点,然后每次查询前都会先进入这个方法

依次运行,发现没有缓存,所以会直接去查数据库

打印了出来的SQL语句:

第二次执行:

因为***次执行时,已经写入缓存了。所以第二次直接从缓存中取数据

3、取两次的结果进行地址的对比:

发现两个不是同一个对象,没错,是对的。如果是使用Ehcache的 话,那么二者的内存地址会是一样的。那是因为redis和ehcache使用的缓存机制是不一样的。ehcache是基于本地电脑的内存使用缓存,所以使 用缓存取数据时直接在本地电脑上取。转换成java对象就会是同一个内存地址,而redis它是在装有redis服务的电脑上(一般是另一台电脑),所以 取数据时经过传输到本地,会对应到不同的内存地址,所以用==来比较会返回false。但是它确实是从缓存中去取的,这点我们从上面的断点可以看到。



看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

缓存 数据 方法 配置 内存 类型 支持 结果 地址 工具 文件 电脑 不同 名称 多个 数据库 时间 存储 服务 实用 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海安装网络技术厂家价格 eps加载三维数据库 服务器安全软件代理服务器 内蒙古数据库仪器仪表平台 有关网络安全的诗歌20字 安徽程序软件开发多少钱 软件开发短信接口 北京三盈软件开发 安全的微信小程序服务器托管公司 达梦数据库超管过期 数据存储磁盘阵列属于服务器吗 香港保险软件开发公司 10月份网络安全检查 汽车应用层应用软件开发 山西政府软件开发公司 甘肃便民平台软件开发系统 轻量服务器好用吗 网络安全教育课程报告2000字 ibm服务器导安装图解 太原小店新华互联网科技 网络安全日常管理台账 多米头条软件开发多久了 黄岛区苹果软件开发系统 软件开发工具有哪些平台 股票银行软件开发公司 数据库定义时常用关键字 河北进口软件开发怎么样 淘宝云服务器选什么配置 关于网络安全意识培训的总结 以房互联网科技是干什么的
0