1.常用的redis客户端介绍以及对比

Jedis api 在线网址:http://tool.oschina.net/uploads/apidocs/redis/clients/jedis/Jedis.html
redisson 官网地址:https://redisson.org/redisson
git项目地址:https://github.com/redisson/redisson
lettuce 官网地址:https://lettuce.io/lettuce
git项目地址:https://github.com/lettuce-io/lettuce-core
在springboot2之后,对redis连接的支持,默认就采用了lettuce。这就一定程度说明了lettuce 和Jedis 的优劣。

概念:

  • Jedis:是老牌的Redis的Java实现客户端,提供了比较全面的Redis命令的支持,
  • Redisson:实现了分布式和可扩展的Java数据结构。
  • Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。

优点:

  • Jedis:比较全面的提供了Redis的操作特性
  • Redisson:促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过 Redis支持延迟队列
  • Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作

可伸缩:

  • Jedis:使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。 Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。
  • Redisson:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作
  • Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作 lettuce能够支持redis4,需要java8及以上。lettuce是基于netty实现的与redis进行同步和异步的通信。

lettuce和jedis比较:

  • jedis使直接连接redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个jedis实 例增加物理连接;
  • lettuce的连接是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,
    StatefulRedisConnection是线程安全的,所以一个连接实例可以满足多线程环境下的并发访问,当然这也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。
  • Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

总结:

  • 优先使用Lettuce,如果需要分布式锁,分布式集合等分布式的高级特性,添加Redisson结合使用,因为Redisson本身对字符串的操作支持很差。
  • 在一些高并发的场景中,比如秒杀,抢票,抢购这些场景,都存在对核心资源,商品库存的争夺,控制不好,库存数量可能被减少到负数,出现超卖的情况,或者 产生唯一的一个递增ID,由于web应用部署在多个机器上,简单的同步加锁是无法实现的,给数据库加锁的话,对于高并发,1000/s的并发,数据库可能由行锁变成表锁,性能下降会厉害。那相对而言,redis的分布式锁,相对而言,是个很好的选择,redis官方推荐使用的Redisson就提供了分布式锁和 相关服务。

2.SpringBoot整合Jedis

简介

我们在使用springboot搭建微服务的时候,在很多时候还是需要redis的高速缓存来缓存一些数据,存储一些高频率访问的数据,如果直接使用redis的话又比较麻烦,在这里,我们使用jedis来实现redis缓存来达到高效缓存的目的

引入Jedis依赖

<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId>
</dependency>

因为 SpringBoot 内默认引用了jedis版本。 所以我们直接引入jedis 依赖 无需在配置 jedis的版本号了。

application.yml

spring:redis:port: 6379password: 123456host: 192.168.20.135jedis:pool:max-idle: 6 #最大空闲数 max-active: 10 #最大连接数 min-idle: 2 #最小空闲数 timeout: 2000 #连接超时

编写Config

@Configuration
public class JedisConfig {private Logger logger = LoggerFactory.getLogger(JedisConfig.class);@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;@Value("${spring.redis.password}")private String password;@Value("${spring.redis.timeout}")private int timeout;@Value("${spring.redis.jedis.pool.max-active}")private int maxActive;@Value("${spring.redis.jedis.pool.max-idle}")private int maxIdle;@Value("${spring.redis.jedis.pool.min-idle}")private int minIdle;@Beanpublic JedisPool jedisPool() {JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();jedisPoolConfig.setMaxIdle(maxIdle);jedisPoolConfig.setMinIdle(minIdle);jedisPoolConfig.setMaxTotal(maxActive);JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password);logger.info("JedisPool连接成功:" + host + "\t" + port);return jedisPool;}
}

测试配置

@SpringBootTest
public class JedisApplicationTests {@Autowiredprivate JedisPool jedisPool;@Testpublic void contextLoads() {System.out.println(jedisPool);//在连接池中得到Jedis连接 Jedis jedis = jedisPool.getResource();jedis.set("haha", "你好");jedis.set("name", "aaa");//关闭当前连接 jedis.close();}
}

封装工具类

@Component
public class JedisUtils {private static Logger logger = LoggerFactory.getLogger(JedisUtils.class);private static JedisPool jedisPool = SpringContextHolder.getBean(JedisPool.class);/*** 获取缓存* @param key 键* @return 值*/public static String get(String key) {String value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {value = jedis.get(key);value = StringUtils.isNotBlank(value)&& !"nil".equalsIgnoreCase(value) ? value : null;logger.debug("get {} = {}", key, value);}} catch (Exception e) {logger.warn("get {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 获取缓存** @param key 键* @return 值*/public static Object getObject(String key) {Object value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {value = toObject(jedis.get(getBytesKey(key)));logger.debug("getObject {} = {}", key, value);}} catch (Exception e) {logger.warn("getObject {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 设置缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String set(String key, String value, int cacheSeconds) {String result = null;Jedis jedis = null;try {jedis = getResource();result = jedis.set(key, value);if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("set {} = {}", key, value);} catch (Exception e) {logger.warn("set {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 设置缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setObject(String key, Object value, int cacheSeconds) {String result = null;Jedis jedis = null;try {jedis = getResource();result = jedis.set(getBytesKey(key), toBytes(value));if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setObject {} = {}", key, value);} catch (Exception e) {logger.warn("setObject {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 获取List缓存** @param key 键* @return 值*/public static List<String> getList(String key) {List<String> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {value = jedis.lrange(key, 0, -1);logger.debug("getList {} = {}", key, value);}} catch (Exception e) {logger.warn("getList {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 获取List缓存** @param key 键* @return 值*/public static List<Object> getObjectList(String key) {List<Object> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {List<byte[]> list = jedis.lrange(getBytesKey(key), 0, -1);value = Lists.newArrayList();for (byte[] bs : list) {value.add(toObject(bs));}logger.debug("getObjectList {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectList {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 设置List缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setList(String key, List<String> value, int cacheSeconds) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {jedis.del(key);}result = jedis.rpush(key, (String[]) value.toArray());if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setList {} = {}", key, value);} catch (Exception e) {logger.warn("setList {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 设置List缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setObjectList(String key, List<Object> value,int cacheSeconds) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {jedis.del(key);}List<byte[]> list = Lists.newArrayList();for (Object o : value) {list.add(toBytes(o));}result = jedis.rpush(getBytesKey(key), (byte[][]) list.toArray());if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setObjectList {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectList {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向List缓存中添加值** @param key   键* @param value 值* @return*/public static long listAdd(String key, String... value) {long result = 0;Jedis jedis = null;try {jedis = getResource();result = jedis.rpush(key, value);logger.debug("listAdd {} = {}", key, value);} catch (Exception e) {logger.warn("listAdd {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向List缓存中添加值** @param key   键* @param value 值* @return*/public static long listObjectAdd(String key, Object... value) {long result = 0;Jedis jedis = null;try {jedis = getResource();List<byte[]> list = Lists.newArrayList();for (Object o : value) {list.add(toBytes(o));}result = jedis.rpush(getBytesKey(key), (byte[][]) list.toArray());logger.debug("listObjectAdd {} = {}", key, value);} catch (Exception e) {logger.warn("listObjectAdd {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 获取缓存** @param key 键* @return 值*/public static Set<String> getSet(String key) {Set<String> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {value = jedis.smembers(key);logger.debug("getSet {} = {}", key, value);}} catch (Exception e) {logger.warn("getSet {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 获取缓存** @param key 键* @return 值*/public static Set<Object> getObjectSet(String key) {Set<Object> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {value = Sets.newHashSet();Set<byte[]> set = jedis.smembers(getBytesKey(key));for (byte[] bs : set) {value.add(toObject(bs));}logger.debug("getObjectSet {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectSet {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 设置Set缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setSet(String key, Set<String> value, int cacheSeconds) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {jedis.del(key);}result = jedis.sadd(key, (String[]) value.toArray());if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setSet {} = {}", key, value);} catch (Exception e) {logger.warn("setSet {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 设置Set缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setObjectSet(String key, Set<Object> value,int cacheSeconds) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {jedis.del(key);}Set<byte[]> set = Sets.newHashSet();for (Object o : value) {set.add(toBytes(o));}result = jedis.sadd(getBytesKey(key), (byte[][]) set.toArray());if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setObjectSet {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectSet {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向Set缓存中添加值** @param key   键* @param value 值* @return*/public static long setSetAdd(String key, String... value) {long result = 0;Jedis jedis = null;try {jedis = getResource();result = jedis.sadd(key, value);logger.debug("setSetAdd {} = {}", key, value);} catch (Exception e) {logger.warn("setSetAdd {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向Set缓存中添加值** @param key   键* @param value 值* @return*/public static long setSetObjectAdd(String key, Object... value) {long result = 0;Jedis jedis = null;try {jedis = getResource();Set<byte[]> set = Sets.newHashSet();for (Object o : value) {set.add(toBytes(o));}result = jedis.rpush(getBytesKey(key), (byte[][]) set.toArray());logger.debug("setSetObjectAdd {} = {}", key, value);} catch (Exception e) {logger.warn("setSetObjectAdd {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 获取Map缓存** @param key 键* @return 值*/public static Map<String, String> getMap(String key) {Map<String, String> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {value = jedis.hgetAll(key);logger.debug("getMap {} = {}", key, value);}} catch (Exception e) {logger.warn("getMap {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 获取Map缓存** @param key 键* @return 值*/public static Map<String, Object> getObjectMap(String key) {Map<String, Object> value = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {value = Maps.newHashMap();Map<byte[], byte[]> map = jedis.hgetAll(getBytesKey(key));for (Map.Entry<byte[], byte[]> e : map.entrySet()) {value.put(StringUtils.toString(e.getKey()),toObject(e.getValue()));}logger.debug("getObjectMap {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectMap {} = {}", key, value, e);} finally {returnResource(jedis);}return value;}/*** 设置Map缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setMap(String key, Map<String, String> value,int cacheSeconds) {String result = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {jedis.del(key);}result = jedis.hmset(key, value);if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setMap {} = {}", key, value);} catch (Exception e) {logger.warn("setMap {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 设置Map缓存** @param key          键* @param value        值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setObjectMap(String key, Map<String, Object> value,int cacheSeconds) {String result = null;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {jedis.del(key);}Map<byte[], byte[]> map = Maps.newHashMap();for (Map.Entry<String, Object> e : value.entrySet()) {map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));}result = jedis.hmset(getBytesKey(key), (Map<byte[], byte[]>) map);if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setObjectMap {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectMap {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向Map缓存中添加值** @param key   键* @param value 值* @return*/public static String mapPut(String key, Map<String, String> value) {String result = null;Jedis jedis = null;try {jedis = getResource();result = jedis.hmset(key, value);logger.debug("mapPut {} = {}", key, value);} catch (Exception e) {logger.warn("mapPut {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 向Map缓存中添加值** @param key   键* @param value 值* @return*/public static String mapObjectPut(String key, Map<String, Object> value) {String result = null;Jedis jedis = null;try {jedis = getResource();Map<byte[], byte[]> map = Maps.newHashMap();for (Map.Entry<String, Object> e : value.entrySet()) {map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));}result = jedis.hmset(getBytesKey(key), (Map<byte[], byte[]>) map);logger.debug("mapObjectPut {} = {}", key, value);} catch (Exception e) {logger.warn("mapObjectPut {} = {}", key, value, e);} finally {returnResource(jedis);}return result;}/*** 移除Map缓存中的值** @param key   键* @param value 值* @return*/public static long mapRemove(String key, String mapKey) {long result = 0;Jedis jedis = null;try {jedis = getResource();result = jedis.hdel(key, mapKey);logger.debug("mapRemove {}  {}", key, mapKey);} catch (Exception e) {logger.warn("mapRemove {}  {}", key, mapKey, e);} finally {returnResource(jedis);}return result;}/*** 移除Map缓存中的值** @param key   键* @param value 值* @return*/public static long mapObjectRemove(String key, String mapKey) {long result = 0;Jedis jedis = null;try {jedis = getResource();result = jedis.hdel(getBytesKey(key), getBytesKey(mapKey));logger.debug("mapObjectRemove {}  {}", key, mapKey);} catch (Exception e) {logger.warn("mapObjectRemove {}  {}", key, mapKey, e);} finally {returnResource(jedis);}return result;}/*** 判断Map缓存中的Key是否存在** @param key   键* @param value 值* @return*/public static boolean mapExists(String key, String mapKey) {boolean result = false;Jedis jedis = null;try {jedis = getResource();result = jedis.hexists(key, mapKey);logger.debug("mapExists {}  {}", key, mapKey);} catch (Exception e) {logger.warn("mapExists {}  {}", key, mapKey, e);} finally {returnResource(jedis);}return result;}/*** 判断Map缓存中的Key是否存在** @param key   键* @param value 值* @return*/public static boolean mapObjectExists(String key, String mapKey) {boolean result = false;Jedis jedis = null;try {jedis = getResource();result = jedis.hexists(getBytesKey(key), getBytesKey(mapKey));logger.debug("mapObjectExists {}  {}", key, mapKey);} catch (Exception e) {logger.warn("mapObjectExists {}  {}", key, mapKey, e);} finally {returnResource(jedis);}return result;}/*** 删除缓存** @param key 键* @return*/public static long del(String key) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(key)) {result = jedis.del(key);logger.debug("del {}", key);} else {logger.debug("del {} not exists", key);}} catch (Exception e) {logger.warn("del {}", key, e);} finally {returnResource(jedis);}return result;}/*** 删除缓存** @param key 键* @return*/public static long delObject(String key) {long result = 0;Jedis jedis = null;try {jedis = getResource();if (jedis.exists(getBytesKey(key))) {result = jedis.del(getBytesKey(key));logger.debug("delObject {}", key);} else {logger.debug("delObject {} not exists", key);}} catch (Exception e) {logger.warn("delObject {}", key, e);} finally {returnResource(jedis);}return result;}/*** 缓存是否存在** @param key 键* @return*/public static boolean exists(String key) {boolean result = false;Jedis jedis = null;try {jedis = getResource();result = jedis.exists(key);logger.debug("exists {}", key);} catch (Exception e) {logger.warn("exists {}", key, e);} finally {returnResource(jedis);}return result;}/*** 缓存是否存在** @param key 键* @return*/public static boolean existsObject(String key) {boolean result = false;Jedis jedis = null;try {jedis = getResource();result = jedis.exists(getBytesKey(key));logger.debug("existsObject {}", key);} catch (Exception e) {logger.warn("existsObject {}", key, e);} finally {returnResource(jedis);}return result;}/*** 获取资源** @return* @throws JedisException*/public static Jedis getResource() throws JedisException {Jedis jedis = null;try {jedis = jedisPool.getResource();// logger.debug("getResource.", jedis);} catch (JedisException e) {logger.warn("getResource.", e);returnBrokenResource(jedis);throw e;}return jedis;}/*** 归还资源** @param jedis* @param isBroken*/public static void returnBrokenResource(Jedis jedis) {if (jedis != null) {jedisPool.returnBrokenResource(jedis);}}/*** 释放资源** @param jedis* @param isBroken*/public static void returnResource(Jedis jedis) {if (jedis != null) {jedisPool.returnResource(jedis);}}/*** 获取byte[]类型Key** @param key* @return*/public static byte[] getBytesKey(Object object) {if (object instanceof String) {return StringUtils.getBytes((String) object);} else {return ObjectUtils.serialize(object);}}/*** Object转换byte[]类型** @param key* @return*/public static byte[] toBytes(Object object) {return ObjectUtils.serialize(object);}/*** byte[]型转换Object** @param key* @return*/public static Object toObject(byte[] bytes) {return ObjectUtils.unserialize(bytes);}}

测试JedisUtils

@SpringBootTest
public class JedisTests {@Autowiredprivate JedisUtils jedisUtils;@Testvoid test() {String val = jedisUtils.set("key", "value" 10);System.out.println(jedisUtils.get("key"));}
}

3. SpringBoot2.x中redis使用(lettuce)

java代码操作Redis,需要使用Jedis,也就是redis支持java的第三方类库 注意:Jedis2.7以上的版本才支持集群操作

maven配置

<dependencies><!--默认是lettuce客户端--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--redis依赖commons-pool 这个依赖一定要添加--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><!--测试库依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

配置文件配置

spring:# redis 配置redis:# 地址host: localhost# 端口,默认为6379port: 6379# 密码password:# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 8# #连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms

redis配置类

JdbcTemplate–>JDBC 进一步封装。
RedisTemplate–>redis进行了进一步封装 (lettuce)

** 简介**

编写缓存配置类RedisConfig用于调优缓存默认配置,RedisTemplate<String, Object>的类型兼容性更高
大家可以看到在redisTemplate()这个方法中用JacksonJsonRedisSerializer更换掉了Redis默认的序列化方式:JdkSerializationRedisSerializer
spring-data-redis中序列化类有以下几个:

  • GenericToStringSerializer:可以将任何对象泛化为字符创并序列化
  • Jackson2JsonRedisSerializer:序列化Object对象为json字符创(与JacksonJsonRedisSerializer相同)
  • JdkSerializationRedisSerializer:序列化java 对象
  • StringRedisSerializer:简单的字符串序列化
  • JdkSerializationRedisSerializer序列化被序列化对象必须实现Serializable接口,被序列化除属性内容还有其他内容,长度长且不易阅读,默认就是采用这种序列化方式
  • JacksonJsonRedisSerializer序列化,被序列化对象不需要实现Serializable接口,被序列化的结果清晰,容易阅读,而且存储字节少,速度快存储内容如下:"{“userName”:“guoweixin”,“age”:20}"
  • StringRedisSerializer序列化一般如果key、value都是string字符串的话,就是用这个就可以了

RedisConfig类

@Configuration
public class RedisConfig extends CachingConfigurerSupport {/*** 自定义缓存key的生成策略。默认的生成策略是看不懂的(乱码内容) 通过Spring 的依赖注入特性进行自定义的 配置注入并且此类是一个配置类可以更多程度的自定义配置 ** @return */@Bean@Overridepublic KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {StringBuilder sb = new StringBuilder();sb.append(target.getClass().getName());sb.append(method.getName());for (Object obj : params) {sb.append(obj.toString());}return sb.toString();}};}/*** 缓存配置管理器 */@Beanpublic CacheManager cacheManager(LettuceConnectionFactory factory) {//以锁写入的方式创建RedisCacheWriter对象 RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);//创建默认缓存配置对象 RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();RedisCacheManager cacheManager = new RedisCacheManager(writer, config);return cacheManager;}@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();// 在使用注解@Bean返回RedisTemplate的时候,同时配置hashKey与hashValue的序列化方式。 // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer);// value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer);// hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer);// hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}
}

测试

@Log
@Service
public class RedisServiceImpl {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 普通缓存放入 * @param key 键 * @return true成功 false失败 */public String getString(String key) {if (redisTemplate.hasKey(key)) {log.info("Redis中查询");return (String) redisTemplate.opsForValue().get(key);} else {String val = "guoweixin";redisTemplate.opsForValue().set(key, val);log.info("数据库中查询的");return val;}}/*** 普通缓存放入 * @param key 键 * @param value 值 * @param expireTime 超时时间(秒) * @return true成功 false失败 */public Boolean set(String key, Object value, int expireTime) {try {redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);return true;} catch (Exception e) {e.printStackTrace();return false;}}
}

4.springBoot集成redisson(单机,集群,哨兵)

以下部分参考:https://zhuanlan.zhihu.com/p/47563733
引入依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.8.2</version>
</dependency>

配置文件

application.propertiesspring.redis.database=0
spring.redis.password=
spring.redis.timeout=3000
#sentinel/cluster/single
spring.redis.mode=single
#连接池配置
spring.redis.pool.max-idle=16
spring.redis.pool.min-idle=8
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=3000
spring.redis.pool.conn-timeout=3000
spring.redis.pool.so-timeout=3000
spring.redis.pool.size=10
#单机配置
spring.redis.single.address=192.168.60.23:6379
#集群配置
spring.redis.cluster.scan-interval=1000
spring.redis.cluster.nodes=
spring.redis.cluster.read-mode=SLAVE
spring.redis.cluster.retry-attempts=3
spring.redis.cluster.failed-attempts=3
spring.redis.cluster.slave-connection-pool-size=64
spring.redis.cluster.master-connection-pool-size=64
spring.redis.cluster.retry-interval=1500
#哨兵配置
spring.redis.sentinel.master=business-master
spring.redis.sentinel.nodes=
spring.redis.sentinel.master-onlyWrite=true
spring.redis.sentinel.fail-max=3

配置文件读取
RedisProperties

@ConfigurationProperties(prefix = "spring.redis", ignoreUnknownFields = false)
@Data
@ToString
public class RedisProperties {private int database;/*** 等待节点回复命令的时间。该时间从命令发送成功时开始计时*/private int timeout;private String password;private String mode;/*** 池配置*/private RedisPoolProperties pool;/*** 单机信息配置*/private RedisSingleProperties single;/*** 集群 信息配置*/private RedisClusterProperties cluster;/*** 哨兵配置*/private RedisSentinelProperties sentinel;
}

池配置RedisPoolProperties

@Data
@ToString
public class RedisPoolProperties {private int maxIdle;private int minIdle;private int maxActive;private int maxWait;private int connTimeout;private int soTimeout;/*** 池大小*/private  int size;}

RedisSingleProperties

@Data
@ToString
public class RedisSingleProperties {private  String address;
}

集群配置RedisClusterProperties

@Data
@ToString
public class RedisClusterProperties {/*** 集群状态扫描间隔时间,单位是毫秒*/private int scanInterval;/*** 集群节点*/private String nodes;/*** 默认值: SLAVE(只在从服务节点里读取)设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。* MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取*/private String readMode;/*** (从节点连接池大小) 默认值:64*/private int slaveConnectionPoolSize;/*** 主节点连接池大小)默认值:64*/private int masterConnectionPoolSize;/*** (命令失败重试次数) 默认值:3*/private int retryAttempts;/***命令重试发送时间间隔,单位:毫秒 默认值:1500*/private int retryInterval;/*** 执行失败最大次数默认值:3*/private int failedAttempts;
}

哨兵配置 RedisSentinelProperties

@Data
@ToString
public class RedisSentinelProperties {/*** 哨兵master 名称*/private String master;/*** 哨兵节点*/private String nodes;/*** 哨兵配置*/private boolean masterOnlyWrite;/****/private int failMax;
}

CacheConfiguration

@Configuration
@EnableConfigurationProperties(RedisProperties.class)
public class CacheConfiguration {@AutowiredRedisProperties redisProperties;@Configuration@ConditionalOnClass({Redisson.class})@ConditionalOnExpression("'${spring.redis.mode}'=='single' or '${spring.redis.mode}'=='cluster' or '${spring.redis.mode}'=='sentinel'")protected class RedissonSingleClientConfiguration {/*** 单机模式 redisson 客户端*/@Bean@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "single")RedissonClient redissonSingle() {Config config = new Config();String node = redisProperties.getSingle().getAddress();node = node.startsWith("redis://") ? node : "redis://" + node;SingleServerConfig serverConfig = config.useSingleServer().setAddress(node).setTimeout(redisProperties.getPool().getConnTimeout()).setConnectionPoolSize(redisProperties.getPool().getSize()).setConnectionMinimumIdleSize(redisProperties.getPool().getMinIdle());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}/*** 集群模式的 redisson 客户端** @return*/@Bean@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "cluster")RedissonClient redissonCluster() {System.out.println("cluster redisProperties:" + redisProperties.getCluster());Config config = new Config();String[] nodes = redisProperties.getCluster().getNodes().split(",");List<String> newNodes = new ArrayList(nodes.length);Arrays.stream(nodes).forEach((index) -> newNodes.add(index.startsWith("redis://") ? index : "redis://" + index));ClusterServersConfig serverConfig = config.useClusterServers().addNodeAddress(newNodes.toArray(new String[0])).setScanInterval(redisProperties.getCluster().getScanInterval()).setIdleConnectionTimeout(redisProperties.getPool().getSoTimeout()).setConnectTimeout(redisProperties.getPool().getConnTimeout()).setFailedAttempts(redisProperties.getCluster().getFailedAttempts()).setRetryAttempts(redisProperties.getCluster().getRetryAttempts()).setRetryInterval(redisProperties.getCluster().getRetryInterval()).setMasterConnectionPoolSize(redisProperties.getCluster().getMasterConnectionPoolSize()).setSlaveConnectionPoolSize(redisProperties.getCluster().getSlaveConnectionPoolSize()).setTimeout(redisProperties.getTimeout());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}/**  * 哨兵模式 redisson 客户端* @return*/@Bean@ConditionalOnProperty(name = "spring.redis.mode", havingValue = "sentinel")RedissonClient redissonSentinel() {System.out.println("sentinel redisProperties:" + redisProperties.getSentinel());Config config = new Config();String[] nodes = redisProperties.getSentinel().getNodes().split(",");List<String> newNodes = new ArrayList(nodes.length);Arrays.stream(nodes).forEach((index) -> newNodes.add(index.startsWith("redis://") ? index : "redis://" + index));SentinelServersConfig serverConfig = config.useSentinelServers().addSentinelAddress(newNodes.toArray(new String[0])).setMasterName(redisProperties.getSentinel().getMaster()).setReadMode(ReadMode.SLAVE).setFailedAttempts(redisProperties.getSentinel().getFailMax()).setTimeout(redisProperties.getTimeout()).setMasterConnectionPoolSize(redisProperties.getPool().getSize()).setSlaveConnectionPoolSize(redisProperties.getPool().getSize());if (StringUtils.isNotBlank(redisProperties.getPassword())) {serverConfig.setPassword(redisProperties.getPassword());}return Redisson.create(config);}}
}

使用时候直接注入RedissClient客户端就可以使用,如下这样写的目的是为了统一给其它服务提供接口

 @AutowiredRedissonClient redisson;@RequestMapping(value = "lock", method = RequestMethod.POST, consumes = "application/json;charset=UTF-8", produces = "application/json;charset=UTF-8")public @ResponseBodyServerResponse<RLock> lock(@RequestBody ServerRequest<LockReqBody> req) {return callR(redisson -> {RLock lock = redisson.getLock(req.getReqBody().getLockKey());lock.lock(req.getReqBody().getTimeout(), req.getReqBody().getUnit());return lock;});}//省略部分代码private <R> ServerResponse callR(Function<RedissonClient, R> function) {ServerResponse dv = RespHelper.serverResponse(RespCodeService.ERROR, "");try {long startTime = System.currentTimeMillis();dv = RespHelper.serverResponse(RespCodeService.SUCCESS, function.apply(redisson));logger.info("CALLR METHOD USE TIME:{}", System.currentTimeMillis() - startTime);} catch (Throwable e) {          System.out.println("callR error");}return dv;}

Redis学习(三) - Redis客户端对比及配置(SpringBoot)相关推荐

  1. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  2. Redis学习笔记---Redis的主从复制

    Redis学习笔记-Redis的主从复制 1.Redis的高可用性 高可用性(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性. Rei ...

  3. Redis学习笔记---Redis的模式订阅与退订

    Redis学习笔记-Redis的模式订阅与退订 1.发布订阅简介 发布订阅是一种通信的模式,Redis提供了发布订阅功能,可以用于消息的传输 Redis的发布订阅机制包括三个部分,publisher( ...

  4. Redis学习笔记---Redis的事务

    Redis学习笔记-Redis的事务 1. Redis事务(弱事务)和Mysql事务对比 Atomicity(原子性):构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不执行. Redi ...

  5. Redis学习笔记~Redis在windows环境下的安装

    Redis是一个key-value的存储系统,它最大的特点就是可以将数据序列化到文件中. redis存储在服务器的内存或者文件中,它不是session,不是cookies,它只是个更安全,更稳定,更可 ...

  6. redis学习之——redis.conf配置(基本)文件学习

    # Redis configuration file example# Note on units: when memory size is needed, it is possible to spe ...

  7. 《Redis学习三之面试》

    文章转载自:https://juejin.im/post/5ad6e4066fb9a028d82c4b66 就我个人而言,我觉得Redis的基本使用是我们每个Java程序员都应该会的.另外,如果需要面 ...

  8. 【Redis学习】Redis的安装、管理、适用场合以及使用

    1.Redis概述 我们知道,内存是电脑主板上的存储部件,用于存储当前正在使用的数据和程序,CPU可以与内存直接沟通,所以访问速速非常高:而外存数据必须加载到内存以后程序才能使用.如果把CPU当做一个 ...

  9. Redis学习之Redis概述及原理、基本操作及持久化

    一.Redis介绍 Redis是一个开源的使用ANSI C语言编写.遵守BSD协议.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构服务 ...

  10. Redis系列(三)-Redis哨兵模式(一篇文章让你全面的了解reids哨兵模式)

    哨兵模式概述 举一个通俗易懂的例子 有一个皇帝(master)他有2个儿子,大儿子(slave1)和小儿子(slave2).有一天皇帝离家出走了皇位空虚(master宕机),大儿子和小儿子为了争夺皇位 ...

最新文章

  1. C#基础语法(第三天)
  2. 云原生生态周报 Vol. 11 | K8s 1.16 早知道
  3. 地磅称重软件源码_【漯河衡器】浅谈地磅称重的发展趋势
  4. 7.2 极大似然估计
  5. linux 引导程序修复工具,linux 引导修复工具
  6. groovy.run 脚本_Picocli 2.0:类固醇上的Groovy脚本
  7. MySQL—常用指令总结
  8. 为什么我从Mac切换到Linux
  9. HoverTree开发日志之验证码
  10. UIWebView关于XMLHttpRequest的内存泄漏
  11. Redis3.x 源码安装
  12. 关于RS232芯片和RS485芯片共用一个STM32串口的情况下如何设计电路
  13. Java中Date时区的转换
  14. XMU 1615 刘备闯三国之三顾茅庐(三) 【欧拉函数+快速幂+欧拉定理】
  15. C# 强化系列文章四:匿名方法的使用
  16. 秘猿科技开源 CITA-Monitor
  17. java计算月份所在的季度
  18. stackoverflow 搜索问题技巧
  19. 敏捷项目用户故事地图
  20. KeyXing魔兽显血改键工具|制作过程

热门文章

  1. 从单张图重建三维人体模型综述(一)
  2. centos php ioncube_CentOS 7安装ionCube Loader为php解密组件的方法
  3. 好用的滚动式截图工具picpick
  4. 海岸鸿蒙质检质控样浓度一览表,环境标准样品数值对照表(质控样)
  5. PCI/PCIe接口卡Windows驱动程序(4)- 驱动程序代码(源文件)
  6. html 一键发送给微信朋友圈,微信朋友圈如何转发别人说说(朋友圈一键集赞神器)...
  7. 计算机主机清洁维护,电脑主机日常维护保养
  8. PS案例教程:photoshop路径运算和路径组合操作
  9. codesys 实现冒泡排序
  10. oracle查询锁表SQL