目录

一、Maven依赖

二、Redis配置类

三、使用@Cacheable注解进行数据缓存

四、自定义Redis工具类及使用

4.1 序列化工具类

4.2 redis客户端工具类

4.3 redis客户端工具类使用Demo


在日常的开发中,使用Redis作为缓存中间件来提高查询性能已经很常见。通常为了简化开发,提高开发效率,我们在实际开发中会封装一些工具类来满足我们的诉求。

本文以Java工程为例,介绍基于JedisPool的Redis工具类的使用。

一、Maven依赖

<!-- jedis依赖-->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.3</version>
</dependency>

二、Redis配置类

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*** Redis配置类,Redis集群为主从模式。*/
@Configuration
@Slf4j
@EnableCaching
public class RedisConfig {/*** 30分钟缓存*/public final static Integer SECOND_1800 = 30*60;/*** Redis Host*/@Value("${spring.redis.host}")private String redisHost;/*** Redis Port*/@Value("${spring.redis.port}")private Integer redisPort;/*** Redis Password*/@Value("${spring.redis.password}")private String redisPassWord;/*** jedis pool config* 配置连接池线程数(减少线程的频繁创建带来的开销)、超时时间(提高服务可用性)等参数。* @return*/@Beanpublic JedisPoolConfig jedisPoolConfig() {JedisPoolConfig config = new JedisPoolConfig();// 连接池中最小空闲连接config.setMinIdle(1);// 连接池中最大空闲连接config.setMaxIdle(8);// 连接池最大连接数config.setMaxTotal(8);// 连接池最大堵塞等待时间,2000msconfig.setMaxWaitMillis(2000L);// 获取连接时校验有效性config.setTestOnBorrow(true);// 连接空闲时定时校验有效性config.setTestWhileIdle(true);// 连接空闲时定时校验有效性间隔时间,1分钟config.setTimeBetweenEvictionRunsMillis(1000L*60);return config;}/*** 创建JedisClient* @return*/@Beanpublic JedisClientConfiguration jedisClientConfiguration(JedisPoolConfig jedisPoolConfig) {JedisClientConfiguration.JedisClientConfigurationBuilder builder = JedisClientConfiguration.builder();return builder.usePooling().poolConfig(jedisPoolConfig).build();}/*** 配置Redis连接。* Reids一共提供了RedisStandaloneConfiguration(单节点)、RedisSentinelConfiguration(哨兵)、RedisClusterConfiguration(集群)* @return*/@BeanRedisStandaloneConfiguration redisStandaloneConfiguration() {RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();redisStandaloneConfiguration.setHostName(redisHost);redisStandaloneConfiguration.setPort(redisPort);redisStandaloneConfiguration.setPassword(redisPassWord);return redisStandaloneConfiguration;}/*** 创建jedis客户端* @param redisStandaloneConfiguration redis连接* @param jedisClientConfiguration redis客户端配置* @return*/@Beanpublic JedisConnectionFactory jedisConnectionFactory(RedisStandaloneConfiguration redisStandaloneConfiguration,JedisClientConfiguration jedisClientConfiguration) {log.info("ConnectTimeOut {}",jedisClientConfiguration.getConnectTimeout());log.info("ReadTimeOut {}",jedisClientConfiguration.getReadTimeout());JedisConnectionFactory factory = new JedisConnectionFactory(redisStandaloneConfiguration,jedisClientConfiguration);return factory;}// 为方便使用Spring @Cacheable等注解进行的配置 ----------------------Startpublic final static String CACHE_5MINUTES = "cache:5m";public final static String CACHE_10MINUTES = "cache:10m";public final static String CACHE_30MINUTES = "cache:30m";public final static String CACHE_60MINUTES = "cache:60m";/*** 自定义缓存管理器*/@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();// 生成Set cacheNames = new HashSet<>();cacheNames.add(CACHE_5MINUTES);cacheNames.add(CACHE_10MINUTES);cacheNames.add(CACHE_30MINUTES);cacheNames.add(CACHE_60MINUTES);ConcurrentHashMap configMap = new ConcurrentHashMap<>();// 自定义缓存时间// 5分钟缓存configMap.put(CACHE_5MINUTES, config.entryTtl(Duration.ofMinutes(5L)));// 10分钟缓存configMap.put(CACHE_10MINUTES, config.entryTtl(Duration.ofMinutes(10L)));// 30分钟缓存configMap.put(CACHE_30MINUTES, config.entryTtl(Duration.ofMinutes(30L)));// 60分钟缓存configMap.put(CACHE_60MINUTES, config.entryTtl(Duration.ofMinutes(60L)));
//        //永久 key1 的有效期是永久的
//        configMap.put("distributor", config);// 需要先初始化缓存名称,再初始化其它的配置。RedisCacheManager cacheManager = RedisCacheManager.builder(factory).initialCacheNames(cacheNames).withInitialCacheConfigurations(configMap).build();return cacheManager;}// 以下内容为方便使用Spring @Cacheable等注解进行的配置 ----------------------End
}

三、使用@Cacheable注解进行数据缓存

@Cacheable(value= RedisConfig.CACHE_5MINUTES,key="'hasPermission' + #userId + #uri")
public Boolean hasPermission(String uri, Long userId) {
}

@Cacheable是Spring提供的注解,对于只读的场景使用很方便。但需要注意,如果是在同一个Class中调用这类方法,@Cacheable的切面会失效(即缓存不生效)。@Cacheable注解比较适合在基础的Service层使用。

@Cacheable中,缓存的key也可以自定义生成,下面是一个自定生成器及使用案例,可参考。

/*** 通过类名+方法名+参数值生成key值*/
@Component
public class UserKeyGenerator extends CachingConfigurerSupport {@Beanpublic KeyGenerator cacheKeyGenerator() {return (target,method,params) -> {StringBuffer key = new StringBuffer();String strParams = "";if(params!=null && params.length>0){strParams = Arrays.asList(params).stream().map(String::valueOf).collect(Collectors.joining(","));}key.append(target.getClass().getName() + method.getName() + strParams);return key.toString();};}
} /*** 在@Cacheable中使用cacheKeyGenerator作为缓存key生成器*/
@Cacheable(value= RedisConfig.CACHE_5MINUTES,key="cacheKeyGenerator")
public Boolean hasPermission(String uri, Long userId) {
}

另外@Cacheable方式的加入的缓存如果要进行手动删除,可通过如下方式。

@CacheEvict(cacheNames={RedisConfig.CACHE_5MINUTES,RedisConfig.CACHE_10MINUTES,RedisConfig.CACHE_30MINUTES,RedisConfig.CACHE_60MINUTES},key = "#key")
public String cacheDelete(@RequestParam(value = "key") String key){return "缓存删除成功";
}

四、自定义Redis工具类及使用

在实际的开发场景中,在进行Redis操作时,往往会涉及到一些业务逻辑,这个时候使用类似@Cacheable的注解就显得有些不够灵活。此时可以通过工具类的方式,提高开发的效率。

4.1 序列化工具类

import lombok.extern.slf4j.Slf4j;import java.io.*;/*** 序列化工具* @author zhouhanfei 2021.12.2*/
@Slf4j
public class SerializeUtil {public static byte[] serialize(Object o) {ByteArrayOutputStream out = new ByteArrayOutputStream();try {ObjectOutputStream outo = new ObjectOutputStream(out);outo.writeObject(o);} catch (IOException e) {log.error("serialize exception",e);}return out.toByteArray();}public static Object unSerialize(byte[] b) {ObjectInputStream oin;try {oin = new ObjectInputStream(new ByteArrayInputStream(b));try {return oin.readObject();} catch (ClassNotFoundException e) {log.error("unSerialize readObject exception",e);return null;}} catch (IOException e) {log.error("unSerialize exception",e);return null;}}}

4.2 redis客户端工具类

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** 基于RedisTemplate的Redis工具类*/
@Component
@Slf4j
public class RedisUtil {@Resourceprivate RedisTemplate redisTemplate;/*** 插入(覆盖)某个缓存* @param key* @param value* @param timeToLive 过期时间,单位秒* */public boolean put(String key, Object value, int timeToLive) {if (key == null || value == null) {return false;}if(redisTemplate==null){log.debug("redisTemplate is null");return false;}try {if (timeToLive > 0) {redisTemplate.opsForValue().set(key, value, timeToLive, TimeUnit.SECONDS);}else{redisTemplate.opsForValue().set(key,value);}return true;} catch (Exception e) {log.error("redis util string key put exception", e);}return false;}/*** 插入(覆盖)某个缓存* @param key* @param value* @param timeToLive 过期时间,单位秒* */public boolean put(byte[] key, Object value, int timeToLive) {if (key == null || value == null){return false;}if(redisTemplate==null){log.debug("redisTemplate is null");return false;}try {if (timeToLive > 0) {redisTemplate.opsForValue().set(key, value, timeToLive, TimeUnit.SECONDS);}else{redisTemplate.opsForValue().set(key,value);}return true;} catch (Exception e) {log.error("redis util byte key put exception", e);}return false;}/*** 根据key获取缓存* @param key* */public Object get(String key) {if (key == null) {return null;}if(redisTemplate==null){log.debug("redisTemplate is null");return null;}try {return redisTemplate.opsForValue().get(key);} catch (Exception e) {log.error("redis util get exception", e);return null;}}/*** 根据key获取缓存* @param key* */public byte[] getByte(byte[] key) {if (key == null) {return null;}if(redisTemplate==null){log.debug("redisTemplate is null");return null;}try {return SerializeUtil.serialize(redisTemplate.opsForValue().get(key));} catch (Exception e) {log.error("redis util getByte exception", e);return null;}}/*** 根据key获取缓存* @param key* */public Object get(byte[] key) {if (key == null) {return null;}if(redisTemplate==null){log.debug("redisTemplate is null");return null;}try {return redisTemplate.opsForValue().get(key);} catch (Exception e) {log.error("redis util getObject exception", e);return null;}}/*** 递增某个数据(这个数据没有被序列化,不能用get查询)* @param key* @param delta* @param timeToLive 超时时间,单位秒* @return*/public long incr(String key, long delta, int timeToLive) {if (key == null){return -1;}if(redisTemplate==null){log.debug("redisTemplate is null");return -1;}try {long result = redisTemplate.opsForValue().increment(key,delta);if (timeToLive > 0) {redisTemplate.expire(key, timeToLive, TimeUnit.SECONDS);}return result;} catch (Exception e) {log.error("redis util incr exception", e);return -1;}}/*** 删除某个缓存* @param key* */public boolean delete(String key) {if (key == null) {return false;}if(redisTemplate==null){log.debug("redisTemplate is null");return false;}try {redisTemplate.delete(key);return true;} catch (Exception e) {log.error("redis util delete exception", e);return false;}}/*** 插原子缓存,同名key已存在返回false* @param key* @param value* @param timeToLive 超时时间,单位秒* */public boolean setAtomCache(String key, Object value, int timeToLive) {if (key == null || value == null) {return false;}if(redisTemplate==null){log.debug("redisTemplate is null");return false;}boolean success = false;try {// 不存在则添加缓存success = redisTemplate.opsForValue().setIfAbsent(key, value);} catch (Exception e) {log.error("redis util setAtomCache-setIfAbsent exception", e);}// 如果存活时间大于0,则设置存活时间if (timeToLive > 0){try {redisTemplate.expire(key, timeToLive,TimeUnit.SECONDS);} catch (Exception e) {log.error("redis util setAtomCache-expire exception", e);}}return success;}/*** 判断key是否存在* @param key* @return*/public boolean exists(Object key){return redisTemplate.hasKey(key);}/*** 根据关键值模糊匹配* @param keyPer* @return*/public Set<String> keys(String keyPer){return redisTemplate.keys(keyPer);}

4.3 redis客户端工具类使用Demo

@Resource
private RedisUtil redisUtil;public String useDemo(Long cloudUId) {String key = "xxx";if(redisUtil.exists(key)){return redisUtil.get(key);}String result = db.findById(1);redisUtil.put(key,result,RedisConfig.SECOND_1800);return str;
}

Java开发中的工具类——基于JedisPool的Redis工具类相关推荐

  1. JAVA 开发中常用的工具有哪些?

    Java开发中常用的工具有以下几种: Eclipse:一款非常流行的开发工具,提供了很多方便的功能,如代码自动补全.调试.版本控制等. IntelliJ IDEA:一款功能强大的Java集成开发环境, ...

  2. Java开发中的常见危险信号

    在开发,阅读,复审和维护成千上万行Java代码的几年中,我已经习惯于看到Java代码中的某些" 危险信号 ",这些信号通常(但可能并非总是)暗示着代码问题. 我不是在谈论总是错误的 ...

  3. 【干货】Redis在Java开发中的基本使用和巧妙用法

    Redis是一款高性能的内存数据结构存储系统,能够支持多种数据结构类型,如字符串.哈希.列表.集合.有序集合等,也能够支持高级功能,如事务.发布/订阅.Lua脚本等,具有高可用性.高并发性和可扩展性的 ...

  4. day01--java基础编程:计算机基础知识 ,java语言概述,java开发环境搭建,eclipse概述,创建简单java项目,JDK JRE JVM的关系,java开发中的命名规范,编程风格

    1 Day01–Java开发环境+HelloWorld 1.1 计算机基础知识 资料下载网址:刘沛霞 18600949004 code.tarena.com.cn tarenacode code_20 ...

  5. Java开发中Websocket的技术选型参考

    1. 前言 Websocket是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据 ...

  6. Java开发中更多常见的危险信号

    在< Java开发中的常见危险信号>一文中,我研究了一些不一定本身就是错误或不正确的做法,但它们可能表明存在更大的问题. 这些"红色标记"类似于"代码气味&q ...

  7. java property xml,Java开发中读取XML与properties配置文件的方法

    相关阅读: 1. XML文件: 什么是XML?XML一般是指可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言. 2.XML文件的优点: 1)XML文档内容和结构完 ...

  8. Java开发中常见的危险信号(下)

    本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-3 Dustin Ma ...

  9. Java开发中常见的危险信号

    Dustin Marx是一位专业软件开发者,从业已经有17年的时间,他拥有电子工程学士学位,还是一位MBA.Dustin维护着一个博客,专门介绍软件开发的各个主题.近日,他撰文谈到了Java开发中常见 ...

最新文章

  1. sql中小数位四舍五入控制
  2. (转)PHP5使用cookie时报错 cannot modify header information - headers already sent by (......)
  3. Linux下C语言串口应用编程,Linux下串口C语言编程
  4. Web Js 按键事件……Enter提交事件 Enter Js事件
  5. JavaScript结合Bootstrap仿微信后台多图文界面管理
  6. 力扣 13.罗马数字转整数
  7. ClassFinal 加密 Java class文件工具
  8. Spring Boot + Thymeleaf + Activiti 快速开发平台项目,附源码!
  9. javaweb使用quartz
  10. you-get下载酷我音乐付费歌曲
  11. 阿里云SDK实现短信发送
  12. 阿里云iot事业部一面面经
  13. iphone快捷指令蚂蚁森林能量_iPhone「快捷指令」怎么玩?玩法太多,别让这个功能吃灰...
  14. 猎头是怎么找到合适候选人的?
  15. 作业3 跟踪分析Linux内核的启动过程
  16. java.lang.reflect.AccessibleObject
  17. 计算机网络知识点及例题总结(五)数据链路层与局域网
  18. beyond compare 4 license 过期解决办法
  19. 华为抱歉进程com.android.phone,搬运:华为手机adb工具,可以卸载华为全家桶
  20. 去售楼处看房需要了解哪些楼盘信息

热门文章

  1. JS之Web API
  2. 如何用 Python 画出 69 岁老同志?
  3. Google电面狂出难题,春招比秋招难多了……
  4. MDM经理如何为主要利益相关方加速创造价值 - 第一部分:消除重复的客户信息
  5. Jetson WIFI 驱动安装(intel ax200* or inte 9260* 无线模块)
  6. 新高考3+1+2模式(4选2)全走班自动排课系统7.0(正式版)
  7. python3__深度学习__受限玻尔兹曼机
  8. 图形加速卡技术 [专业的基础技术文章]
  9. 选择IB课程需要慎重
  10. 东南亚双11为什么静悄悄