> 文章列表 > redis笔记——springboot集成redis

redis笔记——springboot集成redis

redis笔记——springboot集成redis

Sprigboot整合

springboot整合数据操作一般会通过官方的一个项目springdata来进行整合,它可以操作很多市面上流行的数据库,并且为java程序提供一套完整的统一的api调用。在springboot2版本之后,原本的jedis被替换成功了lettuce。原因是

  • jedis底层是直接reids服务的,多个线程操作不够安全,但如果采用jedis pool连接池又会发生很多问题比如服务占用过大
  • lettuce底层采用netty,一个实例可以在多个线程中共享,不存在线程不安全

原生使用

导入依赖之后在需要使用的类上注入redisTemplate实例即可

package com.zhong;import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;import javax.annotation.Resource;@SpringBootTest
class Redis02SpringbootApplicationTests {//注入操作redis的实例对象@Resourceprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {//		redisTemplate.opsForValue(); //操作string类型
//		redisTemplate.opsForList(); //操作list类型
//		redisTemplate.opsForSet();
//		redisTemplate.opsForZSet();
//		redisTemplate.opsForHash();
//		redisTemplate.opsForGeo();
//		redisTemplate.opsForHyperLogLog();
//		RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); //获得连接,清空数据库都是通过这个连接来进行的
//		connection.flushDb();
//		connection.flushAll();redisTemplate.opsForValue().set("key", "你好,redis");System.out.println(redisTemplate.opsForValue().get("key"));}}

原生客户端连接获取java程序中传递的值会出现中文乱码

在使用java程序对redis注入kv之后,使用redis-cli连接上redis数据库,查看所有的key发现出现了乱码。

127.0.0.1:6379> keys *
1) "user1"
2) "user2"
3) "\\xac\\xed\\x00\\x05t\\x00\\x03key"

这是由于默认的redisTemplate使用的是jdk的序列化,所以就会出现这样的问题。并且如果ava向redis中传递对象,需要把对象序列化才能传递。,或者使用json格式包装对象。我们需要自定义一个序列化方式,于是我们需要自己配置一个redisTemplate。

package com.zhong.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {//为了开发方便一般使用string,objectRedisTemplate<String, Object> template = new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);//json序列化配置(采用fastjson)Jackson2JsonRedisSerializer objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);objectJackson2JsonRedisSerializer.setObjectMapper(om);//string序列化配置StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();//设置普通key的序列化方式为string序列化template.setKeySerializer(stringRedisSerializer);//设置hash的key的序列化方式为string序列化template.setHashKeySerializer(stringRedisSerializer);//设置普通value序列化方式为json序列化template.setValueSerializer(objectJackson2JsonRedisSerializer);//设置hash的value的序列化方式为json序列化template.setHashValueSerializer(objectJackson2JsonRedisSerializer);template.afterPropertiesSet();//新版本可以直接new这个实例作为json序列化方式,默认配置好了配置GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();return template;}
}

测试

package com.zhong;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhong.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;import javax.annotation.Resource;@SpringBootTest
class Redis02SpringbootApplicationTests {@Resource@Qualifier("redisTemplate")private RedisTemplate redisTemplate;@Testpublic void TestObject() throws JsonProcessingException {User zhong = new User("zhong", 3);
//    String s = new ObjectMapper().writeValueAsString(zhong);redisTemplate.opsForValue().set("user", zhong);System.out.println(redisTemplate.opsForValue().get("user"));}}
127.0.0.1:6379> keys *
1) "user"
127.0.0.1:6379> get user
"[\\"com.zhong.pojo.User\\",{\\"name\\":\\"zhong\\",\\"age\\":3}]"

发现在原来的reidis客户端中也能正常显示中文了

封装工具类

在原生的redisTemplate代码中使用get和set方法过于麻烦,我们可以使用一些封装好的工具类来简化操作,在工具类中直接注入我们自定义好的redisTemplate,并且将这个工具类注册为组件,方便我们在后来的类中直接注入而不是new出来

package com.zhong.utils;import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/* @author pancm* @Title: RedisUtil* @Description: redis工具类* @Version:1.0.0* @date 2018年6月7日*/
@Component
@Slf4j
public class RedisUtil {@Resourceprivate RedisTemplate<String, Object> redisTemplate;// =============================common============================/* 指定缓存失效时间 @param key  键* @param time 时间(秒)* @return*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 判断key是否过期 @param key* @return*/public boolean isExpire(String key) {return getExpire(key) > 1 ? false : true;}/* 根据key 获取过期时间 @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/* 判断key是否存在 @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {log.error(e.getMessage());return false;}}/* 删除缓存 @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));}}}// ============================String=============================/* 普通缓存获取 @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/* 普通缓存放入 @param key   键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 普通缓存放入并设置时间 @param key   键* @param value 值* @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 普通缓存放入并设置时间 @param key   键* @param value 值* @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time, TimeUnit timeUnit) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, timeUnit);} else {set(key, value);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 递增 @param key 键* @param by  要增加几(大于0)* @return*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/* 递减 @param key 键* @param by  要减少几(小于0)* @return*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}// ================================Map=================================/* HashGet @param key  键 不能为null* @param item 项 不能为null* @return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/* 获取hashKey对应的所有键值 @param key 键* @return 对应的多个键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/* HashSet @param key 键* @param map 对应多个键值* @return true 成功 false 失败*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* HashSet 并设置时间 @param key  键* @param map  对应多个键值* @param time 时间(秒)* @return true成功 false失败*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 向一张hash表中放入数据,如果不存在将创建 @param key   键* @param item  项* @param value 值* @return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 向一张hash表中放入数据,如果不存在将创建 @param key   键* @param item  项* @param value 值* @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间* @return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 删除hash表中的值 @param key  键 不能为null* @param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}/* 判断hash表中是否有该项的值 @param key  键 不能为null* @param item 项 不能为null* @return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/* hash递增 如果不存在,就会创建一个 并把新增后的值返回 @param key  键* @param item 项* @param by   要增加几(大于0)* @return*/public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);}/* hash递减 @param key  键* @param item 项* @param by   要减少记(小于0)* @return*/public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);}// ============================set=============================/* 根据key获取Set中的所有值 @param key 键* @return*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {log.error(e.getMessage());return null;}}/* 根据value从一个set中查询,是否存在 @param key   键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {log.error(e.getMessage());return false;}}/* 将数据放入set缓存 @param key    键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {log.error(e.getMessage());return 0;}}/* 将set数据放入缓存 @param key    键* @param time   时间(秒)* @param values 值 可以是多个* @return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count = redisTemplate.opsForSet().add(key, values);if (time > 0) {expire(key, time);}return count;} catch (Exception e) {log.error(e.getMessage());return 0;}}/* 获取set缓存的长度 @param key 键* @return*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {log.error(e.getMessage());return 0;}}/* 移除值为value的 @param key    键* @param values 值 可以是多个* @return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {log.error(e.getMessage());return 0;}}// ===============================list=================================/* 获取list缓存的内容 @param key   键* @param start 开始* @param end   结束 0 到 -1代表所有值* @return*/public List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {log.error(e.getMessage());return null;}}/* 获取list缓存的长度 @param key 键* @return*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {log.error(e.getMessage());return 0;}}/* 通过索引 获取list中的值 @param key   键* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推* @return*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {log.error(e.getMessage());return null;}}/* 将list放入缓存 @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 将list放入缓存 @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, Object value, long time) {try {redisTemplate.opsForList().rightPush(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 将list放入缓存 @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 将list放入缓存 @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, List<Object> value, long time) {try {redisTemplate.opsForList().rightPushAll(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 根据索引修改list中的某条数据 @param key   键* @param index 索引* @param value 值* @return*/public boolean lUpdateIndex(String key, long index, Object value) {try {redisTemplate.opsForList().set(key, index, value);return true;} catch (Exception e) {log.error(e.getMessage());return false;}}/* 移除N个值为value @param key   键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lRemove(String key, long count, Object value) {try {Long remove = redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {log.error(e.getMessage());return 0;}}}