Java基于springredis集成SpringBoot操作Redis
本文章为系列文章,如需系统观看请按照文章顺序阅读,如有所了解,解决针对性问题,可直接阅读,谢谢支持!前言
Java操作Redis有很多种方式,主要有Jedis,redisson,lettuce等还有Spring家族的spring-data-redisJedis
是Redis的Java实现客户端,提供了比较全面的Redis命令的支持Redisson
实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,延迟队列Lettuce
用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器,主要在一些分布式缓存框架上使用比较多spring-data-redisSpring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象类似于Spring Framework对JDBC支持一样项目主页: http://projects.spring.io/spring-data-redis/项目文档: http://docs.spring.io/spring-data/redis/docsSpring Data Redis使得在Spring应用中读写Redis数据库更加容易。Spring Data Redis提供了四种Redis服务的Java客户端包的集成,分别是 Jedis ,JRedis , SRP and Lettuce
一般我们都会选择 spring-data-redis 核心对象RedisConnectionFactory
redis的连接工厂类,根据Redis配置连接上Redis服务RedisTemplate
熟悉Spring操作JDBC都知道JdbcTemplate作用,这个类也一样,spring 封装了 RedisTemplate 对象来进行对redis的各种操作,它支持所有的 redis 原生的 apiOperation
针对Jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口ValueOperations:String类型数据操作HashOperations:针对map类型的数据操作ListOperations:针对list类型的数据操作SetOperations:set类型数据操作ZSetOperations:zset类型数据操作BoundKeyOperations
提供了对key的bound(绑定)便捷化操作API,可以通过bound封装指定的key,然后进行一系列的操作而无须"显式"的再次指定KeyBoundValueOperations:Redis String/Value key 约束BoundHashOperations:Redis Hash key 约束BoundListOperations:Redis List key 约束BoundSetOperations:Redis Set key 约束BoundZSetOperations:Redis Sort Set key 约束RedisTemplate序列化问题介绍
当数据存储到Redis时,键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer ,StringRedisTemplate默认使用的是StringRedisSerializer 问题
spring-data-redis中redisTemplate默认使用JDK的序列化策略,会出现两个问题使用redis-cli或者可视化工具查看数据时,不管是key还是value头部都会携带很多特殊字符,不易查看 ,Java代码中获取数据时不受影响,但是对运维来说就不友好了JDK Serializer太费资源解决使用Jackson serializer 替代JDK SerializerStringRedisSerializer结合GenericJackson2JsonRedisSerializerspring-data-redis支持的序列化策略
spring-data-redis默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略GenericToStringSerializer:可以将任何对象泛化为字符串并序列化Jackson2JsonRedisSerializer:跟JacksonJsonRedisSerializer实际上是一样的JacksonJsonRedisSerializer:序列化object对象为json字符串JdkSerializationRedisSerializer:序列化java对象(被序列化的对象必须实现Serializable接口)StringRedisSerializer:简单的字符串序列化GenericToStringSerializer:类似StringRedisSerializer的字符串序列化GenericJackson2JsonRedisSerializer:类似Jackson2JsonRedisSerializer,但使用时构造函数不用特定的类
key和hashKey:推荐使用 StringRedisSerializer: 简单的字符串序列化
value和hashValue:推荐使用Jackson2JsonRedisSerializerRedisTemplate和StringRedisTemplate的区别两者的关系是StringRedisTemplate继承RedisTemplate。两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存
当你的redis数据库里面本来存的是字符串数据或者你要存取的数据就是字符串类型数据的时候,那么你就使用StringRedisTemplate即可,但是如果你的数据是复杂的对象类型,而取出的时候又不想做任何的数据转换,直接从Redis里面取出一个对象,那么使用RedisTemplate是更好的选择开搞开发环境
SpringBoot2.1.5、Redis5.0.5、Maven3.5.0、mybatis-Plus3.2.0pom依赖 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-redis com.alibaba fastjson 1.2.7 org.springframework.boot spring-boot-starter-test test application.yml文件spring: #Redis配置 redis: host: test201 port: 6379 password: #这些都有默认配置,如果没有特殊需求可不写 #连接超时时间(2.0中该参数的类型为Duration,这里在配置的时候需要指明单位 timeout: 2000ms #连接池最大连接数(使用负值表示没有限制) max-active: 8 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms #连接池中的最大空闲连接 max-idle: 8 #连接池中的最小空闲连接 min-idle: 0RedisConfig配置类
上边咱们说默认的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 redisTemplate(RedisConnectionFactory connectionFactory){ //创建原生的RedisTemplate对象 RedisTemplate redisTemplate = new RedisTemplate(); //设置连接工厂 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.tian.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 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 studentList = new ArrayList<>(); Cursor> student = redisUtil.getSome("student", Student.class); while (student.hasNext()){ System.out.println(student.getCursorId()); Map.Entry next = student.next(); Student student1 = (Student) next.getValue(); studentList.add(student1); } for (Student student1 : studentList) { System.out.println(student1); } }RedisUtil类
封装一些常用的操作,大家可以根据自己的需求进行封装,这个作为参考吧package com.tian.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 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