spring boot 整合redis
前言
本文只适用于初学redis的同学,旨在能够运行项目即可,想进行深入了解的同学,本文可能不会给你带来任何价值
准备工作
1.本文中涉及的项目是基于spring boot2.x,并且配置了web模块,在开始之前请准备好你的代码环境。
2.同时,暂时请忘掉你在之前查阅过的,不能使你的项目正常运行的文章。因为一些先入为主的概念,可能会让你变得疑惑,请完全跟随本文的脚步
你必须要了解的一些关系
1.springboot整合redis的两种连接方式
jedis:多线程下,非线程安全,所以使用连接池(不支持异步操作),适用springboot1.x
lettuce:多线程下,线程安全,基于Netty支持异步操作,适用springboot2.x0
2. spring boot2.x 默认使用lettuce连接,spring-boot-starter-data-redis集成了lettuce-core,引入spring-boot-starter-data-redis之后就不需要引入lettuce-core了,但是版本的lettuce-core需要commons-pool2。
3.本文项目使用lettuce方式连接
所需的依赖
//<!--redis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
//<!-- 高版本redis的lettuce需要commons-pool2 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency>
在application.properties中添加配置
//application.properties
#我们这里只配置必须的一些配置,先让项目运行起来,在做拓展 #配置redis信息 #redis服务器地址 spring.redis.host=127.0.0.1 #redis服务器端口 spring.redis.port=6379 spring.redis.password=123456789
在application.properties配置后,并不意味着,spring boot会自动为我们配置redis连接,我们还需要定义一个配置类RedisConf
package com.example.demo; 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; @Configuration //使用注解注入配置,必须要添加,这样application.properties中的配置才能在redis中生效,添加@Configuration之后,spring 会自动扫描注入 public class RedisConf { @Bean //声明一个Bean 这样其他地方可以通过@Autowired获取到生成的 RedisTemplate 对象 public RedisTemplate rt(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate(); template.setConnectionFactory(factory);// 配置连接工厂
//设置键值默认序列化方式
RedisSerializer stringSerializer = new StringRedisSerializer(); //RedisTemplate有自己的默认序列化的方式,不过使用默认方式,会在redis客户端查看的时候出现乱码,不便与使用,我们这里用falstjson库
template.setDefaultSerializer(stringSerializer);
return template; } }
测试是否成功
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.TimeUnit; @RestController public class Index { @Autowired RedisTemplate rt; //装配之前定义的@bean @RequestMapping("/index") public String index() { //测试redis 是否配置成功 rt.opsForValue().set("key001", "测试数据 key值是key001", 500, TimeUnit.MINUTES); System.out.println(rt.opsForValue().get("key001")); return "执行成功"; } }
拓展
1.redis常用配置
# Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=127.0.0.1 # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) spring.redis.jedis.pool.max-active=20 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.jedis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.jedis.pool.max-idle=10 # 连接池中的最小空闲连接 spring.redis.jedis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=1000
2.RedisTemplate 常用方法
前言:
redis有五种数据类型,下文中的rt为RedisTemplate实例对象。
redis的key值是唯一的,如果为String设置了key001,那么hash类型数据中就不可以在加入key001的key
常用方法:
1. string
(1)增
//写入一个键和值 key,value;如果已经存在key那么会覆盖已有的key值 rt.opsForValue().set(key, "value"); //写入一个key-value,并且设置它的过期时间 rt.opsForValue().set(key, value, 1000, TimeUnit.MILLISECONDS); //将map中的key-value批量添加为redis的key-value;只要redis中已经存在与map相同的key(一个或者多个),那么map中的key-value都不会写入redis;注入成功返回ture,失败则返回false Map valMap = new HashMap(); rt.opsForValue().multiSetIfAbsent(valMap); //将map中的值批量注入redis,和multiSetIfAbsent效果一直,不同的是multiSet,即便redis已经存在map中相同的key,也用map的值会覆盖掉redis中原有的key的值,所以这个方法可以用于key的批量增加,和修改; 无返回值 rt.opsForValue().multiSet(valMap);
(2)删
//删除指定的key rt.delete(key); //批量删除key,其中keys:Collection<K> keys rt.delete(keys);
(3)改
// ps:经测试 无效; 在指定key值后增加字符串 rt.opsForValue().append(key, "新增字符串"); //为key设置过期时间(倒计时),到时间后直接删除key,而非把值变为null rt.expire(key, 2000, TimeUnit.MILLISECONDS); //你也可以直接设置到期的时间 过期直接删除key rt.expireAt(key, new Date()); //如果久的key名存在,则将旧的key名改成新的key名;如果不存在旧的key,那么会抛出异常 rt.rename(oldKey, newKey); //将指定的key,移动到指定的redis数据库中,dbIndex:redis数据库索引 rt.move(key, dbIndex); //将key值转化成byte[],return:byte[],如果不存在key,那么return:null rt.dump(key);
(4)查
//判断是否存在key,return:boolean,存在key返回true,不存在返回false rt.hasKey(key); //批量获取key值,返回一个list<>; rt.opsForValue().multiGet(keys); //通过正则查找匹配的key值,返回一个set集合类型 rt.keys(Pattern.compile(key).pattern()); //获取对应key的值,return:string ,不存在key则null rt.opsForValue().get(key); //返回对应key所储存的值的类型 rt.type(key); //随机取出一个key rt.randomKey(); //设置key过期时间 rt.expire(key, 1000, TimeUnit.MILLISECONDS); //返回对应key值剩余的过期时间,如果不存在key返回-2;如果没有通过expire设置过期时间,则返回-1,表示永久保存 rt.getExpire(key); rt.getExpire(key, TimeUnit.MILLISECONDS);//可以通过第二个参数,设置放回剩余过期时间的单位 //查询对应key的大小,单位为byte rt.opsForValue().size(key);
2. hash
(1)增、改
//在对应key的hash表中注入一个字段为field,值为hash val 001的记录;如果对应key已经存在hash表则在hash表中注入字段;如果hash表中字段已经存在相同,则覆盖对应字段的value rt.opsForHash().put(key, field, "hash val 00"); //在对应key的hash表内,增加一个字段filed,并设置对应字段的filed;仅当对应的filed不存在时才设置 rt.opsForHash().putIfAbsent(key, field, "hash val 01"); //批量添加对应key下hash表中的记录 Map m = new HashMap(); m.put("filed01", "val3"); m.put("filed02", "val4"); rt.opsForHash().putAll(key, m);//如果hash表中已经存在相同的字段,那么对字段的值进行覆盖
(2)删
//删除对应hash表内的一个或多个字段 rt.opsForHash().delete(key, field); String[] str = {"filed01", "filed02"}; rt.opsForHash().delete(key, str);
(3)改
//删除对应hash表内的一个或多个字段 rt.opsForHash().delete(key, field); String[] str = {"filed01", "filed02"}; rt.opsForHash().delete(key, str);
(4)查
//查看指定hash表内的指定字段是否存在 rt.opsForHash().hasKey(key, field); //查询对应key的hash表中的field字段的值 rt.opsForHash().get(key, field); //获取对应key的hash表的所有的字段名 rt.opsForHash().keys(key); //获取对应key的hash表中的所有字段和值对 rt.opsForHash().entries(key);
3. list
(1)增
//在key对应的list的开头位置插入一个元素 rt.opsForList().leftPush(key, "第1次插入的元素"); rt.opsForList().leftPush(key, "指定值", "第2次插入的元素");//在list从左到右顺序,第一个值是"指定值"的元素前面插入值 //在key对应的list的开头位置插入一个元素,不同的是,只有key对应的list存在时,才插入 rt.opsForList().leftPushIfPresent(key, "插入的值"); //在对应key的list中的开头位置批量增加元素;请注意:插入的元素中,越靠前的元素越先插入,这就意味者在list中越晚插入的元素排序位置越靠前 rt.opsForList().leftPushAll(key, "批量插入元素1", "批量插入元素2"); Collection<String> items = new ArrayList<>(); items.add("items01"); items.add("items02"); rt.opsForList().leftPushAll(key, items);//也可以使用集合的方式批量插入 //在对应key的list中的末尾添加元素,和leftPush使用完全一致 rt.opsForList().rightPush(key, "在末尾添加元素"); //在末尾批量添加元素,和leftPushAll使用完全一致,区别是一个是在开头插入,一个实在末尾插入 rt.opsForList().rightPushAll(key, "末尾添加元素1");
(2)删
//删除从0开始第一个值值为value的元素 rt.opsForList().remove(key, 0, value); //只保留对应key的list中index到pivot位置中的元素 rt.opsForList().trim(key, index, pivot); //移除key对应的list的第一个元素 rt.opsForList().leftPop(key); rt.opsForList().leftPop(key, 5000, TimeUnit.MILLISECONDS);//设置三个参数之后,如果没有存在可移除的元素,那么会阻塞当前进程,直到纯在可以移除的元素,或者到达设置的超时时间为止 //移除key对应list的最后一个元素 rt.opsForList().rightPop(key); rt.opsForList().rightPop(key, 1000, TimeUnit.MILLISECONDS); //将key1对应的list的最后一个元素移除,并将其插入key2对应的list的最开头的位置 rt.opsForList().rightPopAndLeftPush(key1, key2); rt.opsForList().rightPopAndLeftPush(key1, key2, 1000, TimeUnit.MILLISECONDS);//设置三个参数之后,如果没有存在可移除的元素,那么会阻塞当前进程,直到纯在可以移除的元素,或者到达设置的超时时间为止
(3)改
//设置指定元素的值 rt.opsForList().set(key, 0, "添加元素 魔改"); //键list中指定位置的元素保留,其余的全部删除 rt.opsForList().trim(key, 0, 5);
(4)查
//获取对应key的list中指定index的元素 rt.opsForList().index(key, index); //获取对应key的list中指定范围的元素 rt.opsForList().range(key, 0, -1); //获取key对应的list内部元素数量 rt.opsForList().size(key);
4. set
(1)增、改
//在key对应的set中增加一个元素或多个元素 rt.opsForSet().add(key, value, "value2", "value3", "value5", "value6", "value7");
(2)删
//删除key对应的set中一个或多个value rt.opsForSet().remove(key, value, value2); //删除set随机的一个元素,并将其返回 rt.opsForSet().pop(key);
(3)查
//获取集合中所有的元素 rs = rt.opsForSet().members(key); //判断集合中是否存在指定的value rt.opsForSet().isMember(key, value); //判断多个个集合的交集,只返回所有集合中都存在的元素 rt.opsForSet().intersect(key, key2); rt.opsForSet().intersect(key, keys); //将key对应的与一个或多个集合中的交集储存到destKey集合中 rt.opsForSet().intersectAndStore(key, key2, destKey);//将key与key2对应集合中元素的交集凡在放在destKey中 rt.opsForSet().intersectAndStore(key, keys, destKey);//将key与keys中多个集合中对应的元素的交集放在destKey中 //获取集合中的差集 rt.opsForSet().difference(key, key2);//比较两个集合的差集 rt.opsForSet().difference(key, keys);//比较多个集合的差集 //随机获取集合中的一个元素 rt.opsForSet().randomMember(key); //随机获取集合中指定个数的元素 rt.opsForSet().randomMembers(key, count); //获取集合内部元素数量 rt.opsForSet().size(key);
5.zSet
(1)增
//在key对应的zSet集合中增加一个元素,score:int 0;在增加元素的过程中,如果zSet已经存在相同的value的元素,那么旧元素的score将会被覆盖 rt.opsForZSet().add(key, value, score);
(2)删
//删除对应的元素; rt.opsForZSet().remove(key, value); rt.opsForZSet().remove(key, value, value2);//批量删除元素 //移除指定索引位置的元素 rt.opsForZSet().removeRange(key, start, end); //移除指定score范围内的元素 rt.opsForZSet().removeRangeByScore(key,min,max);//移除指定score范围内的元素
(3)改
//改变元素的score值 rt.opsForZSet().incrementScore(key, value, 99); //获取多个集合的并集,并将其存储在另一个集合中 rt.opsForZSet().unionAndStore(key, keys, key2);//keys:为字符串或者字符串集合,为字符串集合的时候合并多个集合 //获取多个集合的交集,并将其存储在另一个集合中 rt.opsForZSet().intersectAndStore(key, keys, key2);//使用方式和unionAndStore完全一致
(4)查
//返回指定index范围的元素 int start = 0; int end = -1; rt.opsForZSet().reverseRangeWithScores(key, start, end); //返回元素在集合的排名;排名值为元素从小到大的排列位置,从0号位开始; rt.opsForZSet().rank(key, value); //返回元素在集合的排名,和rank一样,只不过是由大到小排列 rt.opsForZSet().reverseRank(key, value); //返回指定score范围的元素, rt.opsForZSet().reverseRangeByScore(key, 0, 100);//返回score是0-100得元素 rt.opsForZSet().reverseRangeByScore(key, 0, 100, start, count);//可以添加参数,获取指定score区间内,从start号位开始的count个元素 //根据score获取集合元素数量 rt.opsForZSet().count(key, 0, 10); //获取zSet中集合的数量 rt.opsForZSet().size(key); //获取集合中对应得score值 rt.opsForZSet().score(key, value);