redis 学习笔记
参考文档:
Spring Boot StringRedisTemplate常用操作
1. Redis 基础知识
- Redis 是一款高性能的 NOSQL 系列的非关系型数据库。
- NoSQL (Not Only SQL),意即“不仅仅是 SQL”,是一项全新的数据库理念,泛指非关系型的数据库。
- NOSQL 和关系型数据库比较
- 优点:
- 成本:nosql 数据库简单易部署,基本都是开源软件,不需要像使用 Oracle 那样花费大量成本购买使用,相比关系型数据库价格便宜。
- 查询速度:nosql 数据库将数据存储于缓存之中,关系型数据库将数据存储在硬盘中,自然查询速度远不及 nosql 数据库。
- 存储数据的格式:nosql 的存储格式是 key,value 形式、文档形式、图片形式等等,所以可以存储基础类型以及对象或者是集合等各种格式,而数据库则只支持基础类型。
- 扩展性:关系型数据库有类似 join 这样的多表查询机制的限制导致扩展很艰难。
- 缺点:
- 维护的工具和资料有限。
- 不提供对 SQL 的支持,如果不支持 SQL 这样的工业标准,将产生一定用户的学习和使用成本。
- 不提供关系型数据库对事务的处理。
- 非关系型数据库的优势:
- 性能 NOSQL 是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过 SQL 层的解析,所以性能非常高。
- 可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。
- 关系型数据库的优势:
- 复杂查询可以用 SQL 语句方便的在一个表以及多个表之间做非常复杂的数据查询。
- 事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。
- 总结:关系型数据库与 NoSQL 数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合使用 NoSQL 的时候使用 NoSQL 数据库,让 NoSQL 数据库对关系型数据库的不足进行弥补。一般会将数据存储在关系型数据库中,在 NoSQL 数据库中备份存储关系型数据库的数据。
- Redis 是用 C 语言开发的一个开源的高性能键值对(key-value)数据库,官方提供测试数据,50 个并发执行 100000 个请求,读的速度是 110000 次/s,写的速度是 81000 次/s ,且 Redis 通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止 Redis 支持的键值数据类型如下:
- 字符串类型 string
- 哈希类型 hash
- 列表类型 list
- 集合类型 set
- 有序集合类型 sortedset
- Redis 的应用场景
- 缓存(数据查询、短连接、新闻内容、商品内容等等)
- 聊天室的在线好友列表
- 任务队列。(秒杀、抢购、12306 等等)
- 应用排行榜
- 网站访问统计
- 数据过期处理(可以精确到毫秒)
- 分布式集群架构中的 session 分离
2. 主流的 NOSQL 产品
- 键值(Key-Value)存储数据库
- 相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
- 典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
- 数据模型: 一系列键值对
- 优势: 快速查询
- 劣势: 存储的数据缺少结构化
- 列存储数据库
- 相关产品:Cassandra, HBase, Riak
- 典型应用:分布式的文件系统
- 数据模型:以列簇式存储,将同一列数据存在一起
- 优势:查找速度快,可扩展性强,更容易进行分布式扩展
- 劣势:功能相对局限
- 文档型数据库
- 相关产品:CouchDB、MongoDB
- 典型应用:Web 应用(与 Key-Value 类似,Value 是结构化的)
- 数据模型: 一系列键值对
- 优势:数据结构要求不严格
- 劣势: 查询性能不高,而且缺乏统一的查询语法
- 图形(Graph)数据库
- 相关数据库:Neo4J、InfoGrid、Infinite Graph
- 典型应用:社交网络
- 数据模型:图结构
- 优势:利用图结构相关算法。
- 劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。
3. Redis 命令操作
-
Redis 存储的是:key,value 格式的数据,其中 key 都是字符串,value 有 5 种不同的数据结构
- 字符串类型 string
- 哈希类型 hash:map 格式
- 列表类型 list:linkedlist 格式。支持重复元素
- 集合类型 set:不允许重复元素
- 有序集合类型 sortedset:不允许重复元素,且元素有顺序
-
字符串类型 string
- 存储:
set key value
set username zhangsan
- 拉取:
get key
get username
- 删除:
del key
del username
- 存储:
-
哈希类型 hash
- 存储:
hset key field value
hset myhash username lisi
hset myhash password 123
- 获取:
hget key field
: 获取指定的 field 对应的值hget myhash username
hgetall key
:获取所有的 field 和 valuehgetall myhash
- 删除 hash 中值:
hdel key field [field...]
hdel myhash username
- 删除整个 hash:
del key
del myhash
- 存储:
-
列表类型:list:可以添加一个元素到列表的头部(左边)或者尾部(右边)
- 存储:
lpush key value [value...]
:将元素加入列表左表lpush myList a
rpush key value [value...]
:将元素加入列表右边rpush myList c
- 获取:
lrange key start end
:范围获取lrange myList 0 -1
代表获取所有
- 删除
lpop key
: 删除列表最左边的元素,并将元素返回rpop key
: 删除列表最右边的元素,并将元素返回
- 存储:
-
集合类型 set : 不允许重复元素
- 存储:
sadd key member [member...]
- 获取:
smembers key
:获取 set 集合中所有元素 - 删除:
srem key member [member...]
:删除 set 集合中的某个元素
- 存储:
-
有序集合类型 sortedset:不允许重复元素,且元素有顺序。每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。
- 存储:
zadd key score member [score member...]
- 获取:
zrange key start end [withscores]
withscores 代表是否包含分数 - 删除:
zrem key member
- 存储:
-
通用命令
keys *
:查询所有的键type key
:获取键对应的 value 的类型del key [key...]
:删除指定的 key 和所对应的 value
4. Redis 持久化
- Redis 是一个内存数据库,当 Redis 服务器重启,获取电脑重启,数据会丢失,我们可以将 Redis 内存中的数据持久化保存到硬盘的文件中。
- RDB 持久化机制:默认方式,不需要进行配置,默认就使用这种机制
- 在一定的间隔时间中,检测 key 的变化情况,然后持久化数据
- 在 redis.windwos.conf 文件中进行配置
-
1# 900秒内,如果至少1个keys发生改变,则持久化一次 2save 900 1 3# 300秒内,如果至少10个keys发生改变,则持久化一次 4save 300 10 5# 60秒内,如果至少10000个keys发生改变,则持久化一次 6save 60 10000
- 修改完配置以后,重启服务器。
redis-server.exe redis.windows.conf
表示有某个配置文件启动服务器。
- AOF:日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据,效率低。
- 配置文件 redis.windwos.conf
1appendonly no(关闭aof) --> appendonly yes (开启aof) 2# appendfsync always : 每一次操作都进行持久化 3appendfsync everysec : 每隔一秒进行一次持久化 4# appendfsync no : 不进行持久化
- 配置文件 redis.windwos.conf
5. Java 客户端:Jedis
- Jedis: 一款 Java 操作 Redis 数据库的工具。
- 使用步骤:
1//1. 获取连接 2//如果不传参数,默认为localhost和6379端口 3Jedis jedis = new Jedis("localhost",6379); 4//2. 操作 5jedis.set("username","zhangsan"); 6//3. 关闭连接 7jedis.close();
- 操作 string 类型
String set(String key, String value);
返回 OKString get(String key);
返回 valueString setex(String key,int seconds,String value);
设置键值对并指定过期时间,返回 OK
- 操作 hash 类型
Long hset(String key,String field,String value);
返回成功了几行String hget(String key,String field);
返回 valueMap<String,String> hgetall(String key);
Long hdel(String key,String... fields);
返回成功了几行
- 操作 list 类型
Long lpush/rpush(String key,String strings);
String lpop/rpop(String key);
List<String> lrange(String key,long start,long end);
- 操作 set 类型
Long sadd(String key,String... members);
Set<String> smembers(String key);
获取所有值Long srem(String key,String... members);
- 操作 sortedset 类型
Long zadd(String key,double score,String member);
Set<String> zrange(String key,long begin,long end);
Long zrem(String key,String... members);
- Jedis 连接池:JedisPool
-
1//0.创建一个配置对象(可省略) 2JedisPoolConfig config = new JedisPoolConfig(); 3config.setMaxTotal(50); 4config.setMaxIdle(10); 5 6//1.创建Jedis连接池对象 7JedisPool jedisPool = new JedisPool(config,"localhost",6379); 8//2.获取连接 9Jedis jedis = jedisPool.getResource(); 10//3. 使用 11jedis.set("hehe","heihei"); 12//4. 关闭 归还到连接池中 13jedis.close();
- JedisPoolUtils
1package pers.ylq.util; 2 3import redis.clients.jedis.Jedis; 4import redis.clients.jedis.JedisPool; 5import redis.clients.jedis.JedisPoolConfig; 6 7import java.io.IOException; 8import java.io.InputStream; 9import java.util.Properties; 10 11/** 12 JedisPool工具类 13 加载配置文件,配置连接池的参数 14 提供获取连接的方法 15 */ 16public class JedisPoolUtils { 17 18 private static JedisPool jedisPool; 19 20 static{ 21 //读取配置文件 22 InputStream is = JedisPoolUtils.class.getClassLoader().getResourceAsStream("jedis.properties"); 23 //创建Properties对象 24 Properties pro = new Properties(); 25 //关联文件 26 try { 27 pro.load(is); 28 } catch (IOException e) { 29 e.printStackTrace(); 30 } 31 //获取数据,设置到JedisPoolConfig中 32 JedisPoolConfig config = new JedisPoolConfig(); 33 config.setMaxTotal(Integer.parseInt(pro.getProperty("maxTotal"))); 34 config.setMaxIdle(Integer.parseInt(pro.getProperty("maxIdle"))); 35 36 //初始化JedisPool 37 jedisPool = new JedisPool(config,pro.getProperty("host"),Integer.parseInt(pro.getProperty("port"))); 38 } 39 40 /** 41 * 获取连接方法 42 */ 43 public static Jedis getJedis(){ 44 return jedisPool.getResource(); 45 } 46}
-
6. Redis 使用样例
-
1public class ProvinceServiceImpl implements ProvinceService { 2 //声明dao 3 private ProvinceDao dao = new ProvinceDaoImpl(); 4 /** 5 使用redis缓存 6 */ 7 @Override 8 public String findAllJson() { 9 //1.先从redis中查询数据 10 //1.1获取redis客户端连接 11 Jedis jedis = JedisPoolUtils.getJedis(); 12 String province_json = jedis.get("province"); 13 //2判断 province_json 数据是否为null 14 if(province_json == null || province_json.length() == 0){ 15 //redis中没有数据 16 System.out.println("redis中没数据,查询数据库..."); 17 //2.1从数据中查询 18 List<Province> ps = dao.findAll(); 19 //2.2将list序列化为json 20 ObjectMapper mapper = new ObjectMapper(); 21 try { 22 province_json = mapper.writeValueAsString(ps); 23 } catch (JsonProcessingException e) { 24 e.printStackTrace(); 25 } 26 //2.3 将json数据存入redis 27 jedis.set("province",province_json); 28 //归还连接 29 jedis.close(); 30 }else{ 31 System.out.println("redis中有数据,查询缓存..."); 32 } 33 return province_json; 34 } 35}
7. StringRedisTemplate
我们在 spring boot 中集成 redis
Redis 文档中介绍存入或查询可以使 Object 类型,但是实际中用的是 String 类型
POM 依赖
1<!--redis依赖配置-->
2<dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-data-redis</artifactId>
5</dependency>
配置
1spring:
2 redis:
3 host: localhost # Redis服务器地址
4 database: 0 # Redis数据库索引(默认为0)
5 port: 6379 # Redis服务器连接端口
6 password: # Redis服务器连接密码(默认为空)
7 jedis:
8 pool:
9 max-active: 8 # 连接池最大连接数(使用负值表示没有限制)
10 max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)
11 max-idle: 8 # 连接池中的最大空闲连接
12 min-idle: 0 # 连接池中的最小空闲连接
13 timeout: 3000ms # 连接超时时间(毫秒)
注入对象
1@Autowired
2StringRedisTemplate stringRedisTemplate;
Redis Value
1@Test
2public void valueAddResitTest(){
3 stringRedisTemplate.opsForValue().set("key","value");
4}
5
6@Test
7public void valueGetResitTest(){
8 String value = stringRedisTemplate.opsForValue().get("key");
9 logger.info("value:{}", value);
10}
11
12@Test
13public void valueDelResitTest(){
14 stringRedisTemplate.delete("key");
15}
16
17@Test
18public void valueTimeoutResitTest(){
19 stringRedisTemplate.opsForValue().set("timeStep", new Date().getTime()+"", 2 ,TimeUnit.MINUTES);
20}
Redis List
1// list数据类型适合于消息队列的场景:比如12306并发量太高,而同一时间段内只能处理指定数量的数据!必须满足先进先出的原则,其余数据处于等待
2@Test
3public void listPushResitTest(){
4 // leftPush依次由右边添加
5 stringRedisTemplate.opsForList().rightPush("myList","1");
6 stringRedisTemplate.opsForList().rightPush("myList","2");
7 stringRedisTemplate.opsForList().rightPush("myList", "A");
8 stringRedisTemplate.opsForList().rightPush("myList", "B");
9 // leftPush依次由左边添加
10 stringRedisTemplate.opsForList().leftPush("myList", "0");
11}
12
13@Test
14public void listGetListResitTest(){
15 // 查询类别所有元素
16 List<String> listAll = stringRedisTemplate.opsForList().range( "myList", 0, -1);
17 logger.info("list all {}", listAll);
18 // 查询前3个元素
19 List<String> list = stringRedisTemplate.opsForList().range( "myList", 0, 3);
20 logger.info("list limit {}", list);
21}
22
23@Test
24public void listRemoveOneResitTest(){
25 // 删除先进入的B元素
26 stringRedisTemplate.opsForList().remove("myList",1, "B");
27}
28
29@Test
30public void listRemoveAllResitTest(){
31 // 删除所有A元素
32 stringRedisTemplate.opsForList().remove("myList",0, "A");
33}
Redis Hash
1@Test
2public void hashPutResitTest(){
3 // map的key值相同,后添加的覆盖原有的
4 stringRedisTemplate.opsForHash().put("banks:12600000", "a", "b");
5}
6
7@Test
8public void hashGetEntiresResitTest(){
9 // 获取map对象
10 Map<Object, Object> map = stringRedisTemplate.opsForHash().entries("banks:12600000");
11 logger.info("objects:{}", map);
12}
13
14@Test
15public void hashGeDeleteResitTest(){
16 // 根据map的key删除这个元素
17 stringRedisTemplate.opsForHash().delete("banks:12600000", "c");
18}
19
20@Test
21public void hashGetKeysResitTest(){
22 // 获得map的key集合
23 Set<Object> objects = stringRedisTemplate.opsForHash().keys("banks:12600000");
24 logger.info("objects:{}", objects);
25}
26
27@Test
28public void hashGetValueListResitTest(){
29 // 获得map的value列表
30 List<Object> objects = stringRedisTemplate.opsForHash().values("banks:12600000");
31 logger.info("objects:{}", objects);
32}
33
34@Test
35public void hashSize() {
36 // 获取map对象大小
37 long size = stringRedisTemplate.opsForHash().size("banks:12600000");
38 logger.info("size:{}", size);
39}
8. SpringBoot 整合 redis
参考文献:mall整合Redis实现缓存功能
pom 依赖和 redis 配置参考 StringRedisTemplate
添加 Redis 的自定义 key 配置
1# 自定义redis key
2redis:
3 key:
4 prefix:
5 authCode: "portal:authCode:"
6 expire:
7 authCode: 120 # 验证码超期时间
添加 RedisService 接口用于定义一些常用 Redis 操作
1package com.macro.mall.tiny.service;
2
3/**
4 * redis操作Service,
5 * 对象和数组都以json形式进行存储
6 * Created by macro on 2018/8/7.
7 */
8public interface RedisService {
9 /**
10 * 存储数据
11 */
12 void set(String key, String value);
13
14 /**
15 * 获取数据
16 */
17 String get(String key);
18
19 /**
20 * 设置超期时间
21 */
22 boolean expire(String key, long expire);
23
24 /**
25 * 删除数据
26 */
27 void remove(String key);
28
29 /**
30 * 自增操作
31 * @param delta 自增步长
32 */
33 Long increment(String key, long delta);
34
35}
注入 StringRedisTemplate,实现 RedisService 接口
1package com.macro.mall.tiny.service.impl;
2
3import com.macro.mall.tiny.service.RedisService;
4import org.springframework.beans.factory.annotation.Autowired;
5import org.springframework.data.redis.core.StringRedisTemplate;
6import org.springframework.stereotype.Service;
7
8import java.util.concurrent.TimeUnit;
9
10/**
11 * redis操作Service的实现类
12 * Created by macro on 2018/8/7.
13 */
14@Service
15public class RedisServiceImpl implements RedisService {
16 @Autowired
17 private StringRedisTemplate stringRedisTemplate;
18
19 @Override
20 public void set(String key, String value) {
21 stringRedisTemplate.opsForValue().set(key, value);
22 }
23
24 @Override
25 public String get(String key) {
26 return stringRedisTemplate.opsForValue().get(key);
27 }
28
29 @Override
30 public boolean expire(String key, long expire) {
31 return stringRedisTemplate.expire(key, expire, TimeUnit.SECONDS);
32 }
33
34 @Override
35 public void remove(String key) {
36 stringRedisTemplate.delete(key);
37 }
38
39 @Override
40 public Long increment(String key, long delta) {
41 return stringRedisTemplate.opsForValue().increment(key,delta);
42 }
43}
然后在 Controller 调用即可
9. Spring Data Redis
Spring Data Redis 是Spring 框架提供的用于操作Redis的方式
9.1 Spring Cache 操作 redis
当Spring Boot 结合Redis来作为缓存使用时,最简单的方式就是使用Spring Cache了,使用它我们无需知道Spring中对Redis的各种操作,仅仅通过它提供的@Cacheable 、@CachePut 、@CacheEvict 、@EnableCaching等注解就可以实现缓存功能。
9.1.1 常用注解
@EnableCaching
开启缓存功能,一般放在启动类上。
@Cacheable
使用该注解的方法当缓存存在时,会从缓存中获取数据而不执行方法,当缓存不存在时,会执行方法并把返回结果存入缓存中。一般使用在查询方法上
,可以设置如下属性:
- value:缓存名称(必填),指定缓存的命名空间;
- key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
- unless:条件符合则不缓存;
- condition:条件符合则缓存。
其实在数据库中存储的是一个 hash 类型,比如
1@Cacheable(value = "myvalue", key = "#param")
2public Integer methodB(String param) {
3 return 111;
4}
5// 则存储的 key 为 myvalue::param
6
7@Cacheable("myvalue")
8// 若缺失 key, 则缺省按照方法的所有参数进行组合
@CachePut
使用该注解的方法每次执行时都会把返回结果存入缓存中。一般使用在新增方法上
,可以设置如下属性:
- value:缓存名称(必填),指定缓存的命名空间;
- key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
- unless:条件符合则不缓存;
- condition:条件符合则缓存。
@CacheEvict
使用该注解的方法执行时会清空指定的缓存。一般使用在更新或删除方法上
,可以设置如下属性:
- value:缓存名称(必填),指定缓存的命名空间;
- key:用于设置在命名空间中的缓存key值,可以使用SpEL表达式定义;
- condition:条件符合则缓存。
9.1.2 使用步骤
添加依赖
1<!--redis依赖配置-->
2<dependency>
3 <groupId>org.springframework.boot</groupId>
4 <artifactId>spring-boot-starter-data-redis</artifactId>
5</dependency>
配置 redis
1spring:
2 redis:
3 host: 192.168.6.139 # Redis服务器地址
4 database: 0 # Redis数据库索引(默认为0)
5 port: 6379 # Redis服务器连接端口
6 password: # Redis服务器连接密码(默认为空)
7 timeout: 1000ms # 连接超时时间
添加配置类
此时我们就会想到有没有什么办法让 Redis 中存储的数据变成标准的 JSON 格式,然后可以设置一定的过期时间,不设置过期时间容易产生很多不必要的缓存数据。
我们可以通过给 RedisTemplate 设置 JSON 格式的序列化器,并通过配置 RedisCacheConfiguration 设置超时时间来实现以上需求,具体配置类 RedisConfig 代码如下;
1/**
2 * Redis配置类
3 * Created by macro on 2020/3/2.
4 */
5@EnableCaching
6@Configuration
7public class RedisConfig extends CachingConfigurerSupport {
8
9 /**
10 * redis数据库自定义key
11 */
12 public static final String REDIS_KEY_DATABASE="mall";
13
14 @Bean
15 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
16 RedisSerializer<Object> serializer = redisSerializer();
17 RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
18 redisTemplate.setConnectionFactory(redisConnectionFactory);
19 redisTemplate.setKeySerializer(new StringRedisSerializer());
20 redisTemplate.setValueSerializer(serializer);
21 redisTemplate.setHashKeySerializer(new StringRedisSerializer());
22 redisTemplate.setHashValueSerializer(serializer);
23 redisTemplate.afterPropertiesSet();
24 return redisTemplate;
25 }
26
27 @Bean
28 public RedisSerializer<Object> redisSerializer() {
29 //创建JSON序列化器
30 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
31 ObjectMapper objectMapper = new ObjectMapper();
32 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
33 objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
34 serializer.setObjectMapper(objectMapper);
35 return serializer;
36 }
37
38 @Bean
39 public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
40 RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
41 //设置Redis缓存有效期为1天
42 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
43 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1));
44 return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
45 }
46
47}
Service 类
1@Service
2public class PmsBrandServiceImpl implements PmsBrandService {
3 @Autowired
4 private PmsBrandMapper brandMapper;
5
6 @CacheEvict(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id")
7 @Override
8 public int update(Long id, PmsBrand brand) {
9 brand.setId(id);
10 return brandMapper.updateByPrimaryKeySelective(brand);
11 }
12
13 @CacheEvict(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id")
14 @Override
15 public int delete(Long id) {
16 return brandMapper.deleteByPrimaryKey(id);
17 }
18
19 @Cacheable(value = RedisConfig.REDIS_KEY_DATABASE, key = "'pms:brand:'+#id", unless = "#result==null")
20 @Override
21 public PmsBrand getItem(Long id) {
22 return brandMapper.selectByPrimaryKey(id);
23 }
24
25}
9.2 redis 连接池
Lettuce 是一种可伸缩,线程安全,完全非阻塞的 Redis 客户端,多个线程可以共享一个 RedisConnection,它利用 Netty NIO 框架来高效地管理多个连接,从而提供了异步和同步数据访问方式,用于构建非阻塞的反应性应用程序。
导入依赖
1<dependency>
2 <groupId>org.apache.commons</groupId>
3 <artifactId>commons-pool2</artifactId>
4</dependency>
配置文件
1spring:
2 redis:
3 lettuce:
4 pool:
5 max-active: 8 # 连接池最大连接数
6 max-idle: 8 # 连接池最大空闲连接数
7 min-idle: 0 # 连接池最小空闲连接数
8 max-wait: -1ms # 连接池最大阻塞等待时间,负值表示没有限制
9.3 RedisTemplate
Spring Cache 给我们提供了操作 Redis 缓存的便捷方法,但是也有很多局限性。比如说我们想单独设置一个缓存值的有效期怎么办?我们并不想缓存方法的返回值,我们想缓存方法中产生的中间值怎么办?此时我们就需要用到 RedisTemplate 这个类了,接下来我们来讲下如何通过 RedisTemplate 来自由操作 Redis 中的缓存。
RedisService
1/**
2 * redis 操作 Service
3 */
4public interface RedisService {
5
6 /**
7 * 保存属性
8 */
9 void set(String key, Object value, long time);
10
11 /**
12 * 保存属性
13 */
14 void set(String key, Object value);
15
16 /**
17 * 获取属性
18 */
19 Object get(String key);
20
21 /**
22 * 删除属性
23 */
24 Boolean del(String key);
25
26 /**
27 * 批量删除属性
28 */
29 Long del(List<String> keys);
30
31 /**
32 * 设置过期时间
33 */
34 Boolean expire(String key, long time);
35
36 /**
37 * 获取过期时间
38 */
39 Long getExpire(String key);
40
41 /**
42 * 判断是否有该属性
43 */
44 Boolean hasKey(String key);
45
46 /**
47 * 按delta递增
48 */
49 Long incr(String key, long delta);
50
51 /**
52 * 按delta递减
53 */
54 Long decr(String key, long delta);
55
56 /**
57 * 获取Hash结构中的属性
58 */
59 Object hGet(String key, String hashKey);
60
61 /**
62 * 向Hash结构中放入一个属性
63 */
64 Boolean hSet(String key, String hashKey, Object value, long time);
65
66 /**
67 * 向Hash结构中放入一个属性
68 */
69 void hSet(String key, String hashKey, Object value);
70
71 /**
72 * 直接获取整个Hash结构
73 */
74 Map<Object, Object> hGetAll(String key);
75
76 /**
77 * 直接设置整个Hash结构
78 */
79 Boolean hSetAll(String key, Map<String, Object> map, long time);
80
81 /**
82 * 直接设置整个Hash结构
83 */
84 void hSetAll(String key, Map<String, Object> map);
85
86 /**
87 * 删除Hash结构中的属性
88 */
89 void hDel(String key, Object... hashKey);
90
91 /**
92 * 判断Hash结构中是否有该属性
93 */
94 Boolean hHasKey(String key, String hashKey);
95
96 /**
97 * Hash结构中属性递增
98 */
99 Long hIncr(String key, String hashKey, Long delta);
100
101 /**
102 * Hash结构中属性递减
103 */
104 Long hDecr(String key, String hashKey, Long delta);
105
106 /**
107 * 获取Set结构
108 */
109 Set<Object> sMembers(String key);
110
111 /**
112 * 向Set结构中添加属性
113 */
114 Long sAdd(String key, Object... values);
115
116 /**
117 * 向Set结构中添加属性
118 */
119 Long sAdd(String key, long time, Object... values);
120
121 /**
122 * 是否为Set中的属性
123 */
124 Boolean sIsMember(String key, Object value);
125
126 /**
127 * 获取Set结构的长度
128 */
129 Long sSize(String key);
130
131 /**
132 * 删除Set结构中的属性
133 */
134 Long sRemove(String key, Object... values);
135
136 /**
137 * 获取List结构中的属性
138 */
139 List<Object> lRange(String key, long start, long end);
140
141 /**
142 * 获取List结构的长度
143 */
144 Long lSize(String key);
145
146 /**
147 * 根据索引获取List中的属性
148 */
149 Object lIndex(String key, long index);
150
151 /**
152 * 向List结构中添加属性
153 */
154 Long lPush(String key, Object value);
155
156 /**
157 * 向List结构中添加属性
158 */
159 Long lPush(String key, Object value, long time);
160
161 /**
162 * 向List结构中批量添加属性
163 */
164 Long lPushAll(String key, Object... values);
165
166 /**
167 * 向List结构中批量添加属性
168 */
169 Long lPushAll(String key, Long time, Object... values);
170
171 /**
172 * 从List结构中移除属性
173 */
174 Long lRemove(String key, long count, Object value);
175}
RedisServiceImpl
1/**
2 * redis操作实现类
3 */
4@Service
5public class RedisServiceImpl implements RedisService {
6 @Autowired
7 private RedisTemplate<String, Object> redisTemplate;
8
9 @Override
10 public void set(String key, Object value, long time) {
11 redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
12 }
13
14 @Override
15 public void set(String key, Object value) {
16 redisTemplate.opsForValue().set(key, value);
17 }
18
19 @Override
20 public Object get(String key) {
21 return redisTemplate.opsForValue().get(key);
22 }
23
24 @Override
25 public Boolean del(String key) {
26 return redisTemplate.delete(key);
27 }
28
29 @Override
30 public Long del(List<String> keys) {
31 return redisTemplate.delete(keys);
32 }
33
34 @Override
35 public Boolean expire(String key, long time) {
36 return redisTemplate.expire(key, time, TimeUnit.SECONDS);
37 }
38
39 @Override
40 public Long getExpire(String key) {
41 return redisTemplate.getExpire(key, TimeUnit.SECONDS);
42 }
43
44 @Override
45 public Boolean hasKey(String key) {
46 return redisTemplate.hasKey(key);
47 }
48
49 @Override
50 public Long incr(String key, long delta) {
51 return redisTemplate.opsForValue().increment(key, delta);
52 }
53
54 @Override
55 public Long decr(String key, long delta) {
56 return redisTemplate.opsForValue().increment(key, -delta);
57 }
58
59 @Override
60 public Object hGet(String key, String hashKey) {
61 return redisTemplate.opsForHash().get(key, hashKey);
62 }
63
64 @Override
65 public Boolean hSet(String key, String hashKey, Object value, long time) {
66 redisTemplate.opsForHash().put(key, hashKey, value);
67 return expire(key, time);
68 }
69
70 @Override
71 public void hSet(String key, String hashKey, Object value) {
72 redisTemplate.opsForHash().put(key, hashKey, value);
73 }
74
75 @Override
76 public Map<Object, Object> hGetAll(String key) {
77 return redisTemplate.opsForHash().entries(key);
78 }
79
80 @Override
81 public Boolean hSetAll(String key, Map<String, Object> map, long time) {
82 redisTemplate.opsForHash().putAll(key, map);
83 return expire(key, time);
84 }
85
86 @Override
87 public void hSetAll(String key, Map<String, Object> map) {
88 redisTemplate.opsForHash().putAll(key, map);
89 }
90
91 @Override
92 public void hDel(String key, Object... hashKey) {
93 redisTemplate.opsForHash().delete(key, hashKey);
94 }
95
96 @Override
97 public Boolean hHasKey(String key, String hashKey) {
98 return redisTemplate.opsForHash().hasKey(key, hashKey);
99 }
100
101 @Override
102 public Long hIncr(String key, String hashKey, Long delta) {
103 return redisTemplate.opsForHash().increment(key, hashKey, delta);
104 }
105
106 @Override
107 public Long hDecr(String key, String hashKey, Long delta) {
108 return redisTemplate.opsForHash().increment(key, hashKey, -delta);
109 }
110
111 @Override
112 public Set<Object> sMembers(String key) {
113 return redisTemplate.opsForSet().members(key);
114 }
115
116 @Override
117 public Long sAdd(String key, Object... values) {
118 return redisTemplate.opsForSet().add(key, values);
119 }
120
121 @Override
122 public Long sAdd(String key, long time, Object... values) {
123 Long count = redisTemplate.opsForSet().add(key, values);
124 expire(key, time);
125 return count;
126 }
127
128 @Override
129 public Boolean sIsMember(String key, Object value) {
130 return redisTemplate.opsForSet().isMember(key, value);
131 }
132
133 @Override
134 public Long sSize(String key) {
135 return redisTemplate.opsForSet().size(key);
136 }
137
138 @Override
139 public Long sRemove(String key, Object... values) {
140 return redisTemplate.opsForSet().remove(key, values);
141 }
142
143 @Override
144 public List<Object> lRange(String key, long start, long end) {
145 return redisTemplate.opsForList().range(key, start, end);
146 }
147
148 @Override
149 public Long lSize(String key) {
150 return redisTemplate.opsForList().size(key);
151 }
152
153 @Override
154 public Object lIndex(String key, long index) {
155 return redisTemplate.opsForList().index(key, index);
156 }
157
158 @Override
159 public Long lPush(String key, Object value) {
160 return redisTemplate.opsForList().rightPush(key, value);
161 }
162
163 @Override
164 public Long lPush(String key, Object value, long time) {
165 Long index = redisTemplate.opsForList().rightPush(key, value);
166 expire(key, time);
167 return index;
168 }
169
170 @Override
171 public Long lPushAll(String key, Object... values) {
172 return redisTemplate.opsForList().rightPushAll(key, values);
173 }
174
175 @Override
176 public Long lPushAll(String key, Long time, Object... values) {
177 Long count = redisTemplate.opsForList().rightPushAll(key, values);
178 expire(key, time);
179 return count;
180 }
181
182 @Override
183 public Long lRemove(String key, long count, Object value) {
184 return redisTemplate.opsForList().remove(key, count, value);
185 }
186}