点赞多大胆,就有多大产!路漫漫其修远兮,吾将上下而求索,献给每一位技术使用者和爱好者!
干货满满,摆好姿势,点赞发车
Java操作Redis有很多种方式,主要有Jedis
,redisson
,lettuce
等还有Spring家族的spring-data-redis
redis的连接工厂类,根据Redis配置连接上Redis服务
熟悉Spring操作JDBC都知道JdbcTemplate作用,这个类也一样,spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 api
针对Jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations
:String类型数据操作HashOperations
:针对map类型的数据操作ListOperations
:针对list类型的数据操作SetOperations
:set类型数据操作ZSetOperations
:zset类型数据操作提供了对key的bound
(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key
BoundValueOperations
:Redis String/Value key 约束BoundHashOperations
:Redis Hash key 约束BoundListOperations
:Redis List key 约束BoundSetOperations
:Redis Set key 约束BoundZSetOperations
:Redis Sort Set key 约束当数据存储到Redis时,键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer
spring-data-redis中redisTemplate默认使用JDK的序列化策略,会出现两个问题
spring-data-redis默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略
GenericToStringSerializer
:可以将任何对象泛化为字符串并序列化Jackson2JsonRedisSerializer
:跟JacksonJsonRedisSerializer实际上是一样的JacksonJsonRedisSerializer
:序列化object对象为json字符串JdkSerializationRedisSerializer
:序列化java对象(被序列化的对象必须实现Serializable接口)StringRedisSerializer
:简单的字符串序列化GenericToStringSerializer
:类似StringRedisSerializer的字符串序列化GenericJackson2JsonRedisSerializer
:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类key和hashKey
:推荐使用 StringRedisSerializer: 简单的字符串序列化
value和hashValue
:推荐使用Jackson2JsonRedisSerializer
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择
SpringBoot2.1.5、Redis5.0.5、Maven3.5.0、mybatis-Plus3.2.0
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.7version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
spring:
#Redis配置
redis:
host: test201
port: 6379
password:
#这些都有默认配置,如果没有特殊需求可不写
#连接超时时间(2.0中该参数的类型为Duration,这里在配置的时候需要指明单位
timeout: 2000ms
#连接池最大连接数(使用负值表示没有限制)
max-active: 8
#连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
#连接池中的最大空闲连接
max-idle: 8
#连接池中的最小空闲连接
min-idle: 0
上边咱们说默认的RedisTemplate使用的序列化方式是JDK的,会存在特殊字符的问题而且性能损耗较大,我们创建Java Config修改默认实现的RedisTemplate序列化方式
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
/**
* Redis的配置类
* SDR项目操作Redis的话需要使用RedisTemplate对象
* 但是该对象默认使用的数据序列化方法是JDK的,可能会存在特殊字符
*
* key和hashKey 我们推荐使用String序列化
* value 我们推荐是JSON存储,使用Json序列化
*/
//添加Configuration注解,否则该类不会被加载
@Configuration
public class RedisConfig {
/**
* @Bean:创建对象放到IOC容器中
* RedisConnectionFactory:Redis的连接工厂,根据application.yml文件中的Redis的配置做Redis连接和连接池的管理
该对象在项目初始化时被创建,有一个实现类是 LettuceConnectionFactory
*/
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
//创建原生的RedisTemplate对象
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<String,Object>();
//设置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerialize替换 默认的JDK序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//创建JSON序列化的对象,value使用JSON序列化方式
ObjectMapper om = new ObjectMapper();
//设置序列化的策略
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//启用默认的类型
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//引用JSON序列化
jackson2JsonRedisSerializer.setObjectMapper(om);
//创建String序列化,我们的key使用String序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用JSON
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用JSON
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
//使用该配置
redisTemplate.afterPropertiesSet();
//返回修改后的RedisTemplate对象
return redisTemplate;
}
}
package com.zhiyou100.redis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.*;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
import java.util.concurrent.TimeUnit;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Day0512RedisApplicationTests {
@Test
public void contextLoads() {
}
//注入RedisTemplate
@Autowired
private RedisTemplate redisTemplate;
/**
* 操作String
*/
@Test
public void test1(){
//获取操作String'类型的对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//存储数据
try {
valueOperations.set("user1","添哥");
valueOperations.set("user2","小添哥哥");
System.out.println("存储数据成功");
//获取数据
String user1 = (String)valueOperations.get("user1");
String user2 = (String)valueOperations.get("user2");
System.out.println(user1 + "==>" + user2);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 操作list
*/
@Test
public void test2(){
ListOperations operations = redisTemplate.opsForList();
Long num = operations.leftPushAll("l1", "l11", "l22", "l33", "l44");
System.out.println("插入数据个数===》" + num);
//取值
List list = operations.range("l1", 0, -1);
for (Object o : list) {
System.out.println("list---》"+o);
}
}
/**
* 操作set
*/
@Test
public void test3(){
SetOperations operations = redisTemplate.opsForSet();
Long num = operations.add("s1", "s11", "s22", "s33", "s44", "s11", "s22", "s55");
System.out.println(num);
//获取
Set set = operations.members("s1");
for (Object o : set) {
System.out.println(o);
}
}
/**
* 操作zset
*/
@Test
public void test4(){
ZSetOperations operations = redisTemplate.opsForZSet();
operations.add("z1","z10",100.00);
operations.add("z1","z20",200.00);
operations.add("z1","z5",50.00);
//获取值
Set set = operations.range("z1", 0, -1);
for (Object o : set) {
System.out.println(o);
}
}
/**
* 操作Hash
*/
@Test
public void test5(){
HashOperations operations = redisTemplate.opsForHash();
//存储学生1
operations.put("stu:1:info","name","小添");
operations.put("stu:1:info","classRoom","快刀班");
//存储学生2
HashMap<String, Object> map = new HashMap<>();
//添加学生信息
map.put("name","晓添");
map.put("classRoom","吃瓜班");
operations.putAll("stu:2:info",map);
//获取数据1
Object name = operations.get("stu:1:info","name");
Object classRoom = operations.get("stu:1:info","classRoom");
System.out.println("学生1==》"+name+"==>"+classRoom);
//获取数据2
Map entries = operations.entries("stu:2:info");
//遍历map
Set set = entries.keySet();
for (Object o : set) {
System.out.println(o + "==>" + entries.get(o));
}
}
/**
* 对key的操作
*/
@Test
public void test6(){
//判断key是否存在
Boolean hasKey = redisTemplate.hasKey("stu:2:info");
System.out.println("stu:2:info===>"+hasKey);
//设置过期时间,k3键10秒过期
redisTemplate.expire("k3",10, TimeUnit.SECONDS);
//设置l1键在2020 5 13 7点过期
redisTemplate.expireAt("l1",new Date(2020,5,13,7,00,00));
}
}
//下方两个测试是使用RedisUtil中封装使用boundHashOps方式操作
@Test
public void t1(){
Student student = new Student();
student.setId("100");
student.setName("石靓仔");
student.setSex("男");
student.setBirth("1995-06-26");
redisUtil.putSome(Student.class,"student",student.getId(),student);
}
@Test
public void t2(){
List<Student> studentList = new ArrayList<>();
Cursor<Map.Entry<String, Object>> student = redisUtil.getSome("student", Student.class);
while (student.hasNext()){
System.out.println(student.getCursorId());
Map.Entry<String, Object> next = student.next();
Student student1 = (Student) next.getValue();
studentList.add(student1);
}
for (Student student1 : studentList) {
System.out.println(student1);
}
}
封装一些常用的操作,大家可以根据自己的需求进行封装,这个作为参考吧
package com.stt.springbootredis.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* ClassName: RedisUtils
* Description:
* date: 2019/11/11 0011 下午 19:59
*
* @author stt
* @since JDK 1.8
*/
@Component
public class RedisUtil {
@Autowired
public RedisTemplate redisTemplate;
// =============================common============================
/**
26
* 指定缓存失效时间
27
* @param key 键
28
* @param time 时间(秒)
29
* @return
30
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据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) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public boolean del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
return redisTemplate.delete(key[0]);
}
return redisTemplate.delete(CollectionUtils.arrayToList(key)) > 0 ? true : false;
}
return false;
}
/**
* 匹配所有的key
* @param pettern
* @return
*/
public Set<String> keys(String pettern){
if(pettern.trim() != "" && pettern != null){
return redisTemplate.keys(pettern);
}
return null;
}
// ============================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) {
e.printStackTrace();
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) {
e.printStackTrace();
return false;
}
}
/**
* 递增
* @param key 键
* @param delta 要增加几(大于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 delta 要减少几(小于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 List<Object> hmget(String key) {
return redisTemplate.opsForHash().values(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) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
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);
}
/**
* 存储对象
* @param key
* @param field
* @param value
*/
public void putSome(Class cls,String key,String field,Object value){
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(cls));
redisTemplate.boundHashOps(key).put(field,value);
}
/**
* 获取对象
* @param key
* @param cls
* @return
*/
public Cursor<Map.Entry<String,Object>> getSome(String key,Class cls){
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(cls));
Cursor<Map.Entry<String, Object>> scan = redisTemplate.boundHashOps(key).scan(ScanOptions.scanOptions().build());
return scan;
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
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) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
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) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
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) {
e.printStackTrace();
return 0;
}
}
}