目录
一、Redis概述
Redis是用C语言开发的一个开源的高性能基于内存运行的键值对NoSQL数据库,相比于必须按照规定格式存储的关系型数据库而言,非关系型数据库的数据格式更灵活,通常用于查大规模数据的存储。
Redis就是非关系型数据库的一种,它基于内存,数据结构是k-v形式的。主要作用于缓存。Redis是单线程的,在多用户并发操作情况下,它是按序处理完一个再处理另一个请求。可以实现数据持久化和主从复制,除了基本的k-v结构外也支持更复杂的结构。只要开启Master-Slave策略就能够实现数据备份。它的并发能力能达到六七万。
在高并发场景下如果要经常不断查MySQL数据库来取出相同的数据,重复连续的读写操作导致磁盘IO过高,并发能力差。但通过Redis缓存下较为频繁使用的数据后,请求将直接查询Redis里的数据,减少数据库负载,达到有效地提高程序响应速度的目的。
二、Redis的下载和安装
Windows安装: https://github.com/dmajkic/redis/releases
官网:
中文官网:http://redis.cn/topics/introduction
英文官网:http://redis.io/topics/introduction
redis-benchmark.exe 测试性能
redis-check-aof.exe 测试持久化
redis-cli.exe 客户端
redis-server.exe 服务端
三、Redis启动
- redis默认不是后台启动的,修改这个.conf文件
开启守护进程:223行
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no #no改成yes即可开启守护进程 daemonize yes
- 启动redis服务,指定启动的conf文件
redis-server XXX/redis.conf
- 使用redis-cli 进行连接
redis-cli -p 6379
- 查看redis的进程是否开启
ps -ef|grep redis
Redis相关知识:
(1)Redis默认拥有16个数据库,数据库编号从0开始,默认使用0号数据库。conf配置文件可修改数量。
(2)使用select 数据库编号 可以切换使用的数据库
(3)dbsize 命令查看当前数据库key的数量
(4)keys * 命令查看当前数据库所有的key
(5)flushdb 命令清空当前数据库
(6)flushall 命令清空所有数据库
(7)Redis中所有数据库使用同一个密码。默认没有密码,Redis认为安全层面应该由Linux来保证
(8)Redis中所有索引都是从0开始
(9)Redis默认端口是6379
四、Redis五大数据类型及操作
1. redis的数据结构:
redis存储的是:key,value格式的数据。
其中key都是字符串,value有5种不同的数据结构
value的数据结构:
1) 字符串类型 string
2) 哈希类型 hash : map格式
3) 列表类型 list : linkedlist格式。支持重复元素
4) 集合类型 set : 不允许重复元素
5) 有序集合类型 sortedset:不允许重复元素,且元素有顺序
2. 字符串类型 string
1. 存储: set key value
127.0.0.1:6379> set username zhangsan
OK
2. 获取: get key
127.0.0.1:6379> get username
"zhangsan"
3. 删除: del key
127.0.0.1:6379> del age
(integer) 1
3. 哈希类型 hash
1. 存储: hset key field value
127.0.0.1:6379> hset myhash username lisi
(integer) 1
127.0.0.1:6379> hset myhash password 123
(integer) 1
2. 获取:
* hget key field: 获取指定的field对应的值
127.0.0.1:6379> hget myhash username
"lisi"
* hgetall key:获取所有的field和value
127.0.0.1:6379> hgetall myhash
1) "username"
2) "lisi"
3) "password"
4) "123"
3. 删除: hdel key field
127.0.0.1:6379> hdel myhash username
(integer) 1
4. 列表类型 list:
可以添加一个元素到列表的头部(左边)或者尾部(右边)
1. 添加:
1. lpush key value: 将元素加入列表左表
2. rpush key value:将元素加入列表右边
127.0.0.1:6379> lpush myList a
(integer) 1
127.0.0.1:6379> lpush myList b
(integer) 2
127.0.0.1:6379> rpush myList c
(integer) 3
2. 获取:
* lrange key start end :范围获取
127.0.0.1:6379> lrange myList 0 -1
1) "b"
2) "a"
3) "c"
3. 删除:
* lpop key: 删除列表最左边的元素,并将元素返回
* rpop key: 删除列表最右边的元素,并将元素返回
* lrem key count value : 删除key下count数量的value元素
4. 获取个数:
* llen key: 获取元素个数
6. 集合类型 set : 不允许重复元素
1. 存储:sadd key value
127.0.0.1:6379> sadd myset a
(integer) 1
127.0.0.1:6379> sadd myset a
(integer) 0
2. 获取:smembers key:获取set集合中所有元素
127.0.0.1:6379> smembers myset
1) "a"
3. 删除:srem key value:删除set集合中的某个元素
127.0.0.1:6379> srem myset a
(integer) 1
4. 获取个数:
* scard key: 获取元素个数
7. 有序集合类型 sortedset:
【ps:不允许重复元素,且元素有顺序.
每个元素都会关联一个double类型的分数。
redis正是通过分数来为集合中的成员进行从小到大的排序。】
1. 存储:zadd key score value
127.0.0.1:6379> zadd mysort 60 zhangsan
(integer) 1
127.0.0.1:6379> zadd mysort 50 lisi
(integer) 1
127.0.0.1:6379> zadd mysort 80 wangwu
(integer) 1
2. 获取:zrange key start end [withscores]
127.0.0.1:6379> zrange mysort 0 -1
1) "lisi"
2) "zhangsan"
3) "wangwu"
127.0.0.1:6379> zrange mysort 0 -1 withscores
1) "zhangsan"
2) "60"
3) "wangwu"
4) "80"
5) "lisi"
6) "500"
3. 删除:zrem key value
127.0.0.1:6379> zrem mysort lisi
(integer) 1
4. 获取个数:
* zcard key: 获取元素个数
8. 通用命令
1. keys * : 查询所有的键
2. type key : 获取键对应的value的类型
3. del key:删除指定的key value
五、Redis持久化
redis是内存数据库,如果没有持久化,那么数据宕机即失。
持久化概念:利用磁盘等将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。
持久化的两种方式:
(1) 快照
将某个时间点的工作状态保存下来,恢复时可直接恢复指定时间点的工作状态。Redis中这种方式称为RDB。
修改内存中数据保存的文件的名称,默认名为dump.rdb
rdb保存目录
<1>使用bgsave命令保存kv到.rdb文件:
此命令可以手动保存,并让该保存操作在后台执行,redis服务可以继续执行其之后的指令,使用较多。
bgsave指令工作原理:
<2>配置自动保存 (修改配置文件后需要重启Redis)
conf文件中,以“save 900 1”为说明,900s内发现一个key变化(指增删改),Linux则fork()一个进程去保存k-v值在dump.db中。
RDB缺点:
(1) 基于快照思想,每次读写都是全部数据,当数据量较大时,效率非常低
(2) 基于fork创建子进程,内存产生额外的消耗
(3) 宕机带来数据丢失风险(可能某个时间点的数据未保存)
(2) 日志
把对数据的所有 操作的命令 记录下来,恢复数据时 重新执行 这些命令。Redis中这种方式称为AOF。
appendonly no #默认是不开启aof模式的,默认是使用rdb方式持久化的,在大部分所有的情况下,rdb完全够用! 改为yes开启aof功能
appendfilename "appendonly.aof" # 持久化的文件的名字
# appendfsync always # 每次修改都会 sync 消耗性能
appendfsync everysec # 每秒执行一次 sync,可能会丢失这一秒的数据
# appendfsync no # 不执行 sync 操作系统自己同步数据,速度最快,但一般也不用。
如上图:
只许追加文件但不可以改写文件,故而文件会越来越大。如果这个aof文件大于64M。fork一个新的进程来将文件进行重写。
redis启动之初会读取该文件重新构建数据,根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复工作(是大数据就很慢)。
如果aof文件有错误,redis会启动不起来的,需要修复aof文件,redis 提供了一个工具 redis-check-aof --fix
模拟aof出错并修复的步骤:
1.shutdown exit,退出redis
2.删除datas/dump.rdb文件,因为里面有保存数据
3.vim appendonly.aof,肆意修改,并保存
4.尝试启动redis,登录cli的时候报错:
Could not connect to Redis at node1:6379: Connection refused
5.执行修复工具:redis-check-aof --fix …/datas/appendonly.aof
6.需要你确认,输入y,修复成功。Successfully truncated AOF
7.再次执行,如果aof文件正常,就会发现数据都恢复了
【ps:破坏aof文件,在aof文件底部添加数据是可以修复的,但是如果set k1 v1这种的结构破坏了,aof也无法修复,修复了直接是空的数据库。】
官方使用的建议:
通常,要想提供很高的数据保障性,那么建议同时使用两种持久化方式。 如果可以接受灾难带来的几分钟的数据丢失,可以仅使用RDB。 很多用户仅使用了AOF,但是我们建议,既然RDB可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用RDB。
六、redis客户端Jedis和Luttuce
Lettuce 和 Jedis 都是Redis的客户端,客户端连接 Redis 使用的是 TCP协议,可以直接连接redis server。
(1)Jedis
Jedis在实现上是直接连接的redis server,在多线程环境下是非线程安全的,此时使用 连接池 ,为每个Jedis实例增加物理连接。
客户端连接 Redis 使用的是 TCP协议,直连的方式每次需要建立 TCP连接,而 连接池 的方式是可以预先初始化好客户端连接,所以每次只需要从 连接池借用即可,而借用和归还操作是在本地进行的,只有少量的并发同步开销,远远小于新建TCP连接的开销。另外,直连的方式无法限制 redis客户端对象的个数,在极端情况下可能会造成连接泄漏,而连接池的形式可以有效的保护和控制资源的使用。
(2)Lettuce
Lettuce的连接是基于Netty的,连接实例StatefulRedisConnection,可以在多个线程间并发访问。因为StatefulRedisConnection是线程安全的,所以一个连接实例(即StatefulRedisConnection)就可以满足多线程环境下的并发访问,这个是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。lettuce主要利用netty实现与redis的同步和异步通信。
七、使用springboot整合redis客户端:Jedis和Luttuce
使用springboot连接redis的时候,在springboot1.X版本默认使用的是Jedis,但是在springboot2.X版本默认使用Lettuce。
【ps:无论用什么客户端,向redis中存储对象都必须要序列化】
(1)SpringBoot2.X集成Lettuce连接池:
<1>依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<!--lettuce pool連接池-->
<artifactId>commons-pool2</artifactId>
</dependency>
<2> application.properties配置文件
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
# 连接池最大连接数(使用负值表示没有限制) 默认为8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接 默认为8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认为 0
spring.redis.lettuce.pool.min-idle=0
<3>配置redis配置类,自定义 RedisTemplate:
自定义 RedisTemplate ,设置序列化器,方便操作实例对象。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.io.Serializable;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Serializable> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
<4>定义测试实体类
public class User implements Serializable {
private static final long serialVersionUID = 4220515347228129741L;
private Integer id;
private String username;
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
public User() {
}
//getter/setter 省略
}
<5>测试
//@RunWith(SpringRunner.class)表示运行在spring环境下。这时@Aurowried将能注入RedisTemplate
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisTest {
private Logger logger = LoggerFactory.getLogger(RedisTest.class);
@Autowired
private RedisTemplate<String, Serializable> redisTemplate;
@Test
public void test() {
String key = "user:1"; //层级命名,根据业务场景定义
redisTemplate.opsForValue().set(key, new User(1,"花满楼"));
User user = (User) redisTemplate.opsForValue().get(key);
logger.info("uesr: "+user.toString());
}
}
(2)SpringBoot2.X整合Jedis:
因为 springboot2.0中“默认”是使用 Lettuce来集成Redis服务,spring-boot-starter-data-redis默认只引入了 Lettuce包,并没有引入 jedis包支持。所以需要手动引入 jedis的包,并排除掉 lettuce的包。
<1>依赖配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<2>application.properties配置,使用jedis的连接池
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=root
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.max-wait=-1ms
spring.redis.jedis.pool.min-idle=0
spring.redis.jedis.pool.max-active=8
<3>配置redis配置类,自定义 RedisTemplate,Jedis的template使用的连接对象是 JedisConnectionFactory,需要手动配置并注JedisConnectionFactory。
springboot2.x集成Jedis并不会读取配置文件中的 spring.redis.host等此类配置,需要手动给Factory设置值。
@Configuration
public class RedisConfig2 {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.password}")
private String password;
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
//在 springboot 2.x版本中推荐使用 RedisStandaloneConfiguration类来设置连接的端口,地址等属性。
//因为JedisConnectionFactory设置连接的方法已过时
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
//手动设置值
config.setHostName(host);
config.setPort(port);
config.setPassword(RedisPassword.of(password));
JedisConnectionFactory connectionFactory = new JedisConnectionFactory(config);
return connectionFactory;
}
@Bean
public RedisTemplate<String, Serializable> redisTemplate(JedisConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(jedisConnectionFactory());
return redisTemplate;
}
}
(3)为什么要自定义RredisTemplate?
在引入redis的依赖后,RredisTemplate会自动配置,可以直接注入RedisTemplate使用。看源码:
Spring Boot 自动帮我们在容器中生成了一个RedisTemplate和一个StringRedisTemplate。但是,这个RedisTemplate的泛型是<Object,Object>。这样在写代码就很不方便,要写好多类型转换的代码。
@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
因为有@ConditionalOnMissingBean(name = “redisTemplate”)注解,
所以如果在Spring容器中,我们自定义一个name 为“redisTemplate” 的 RedisTemplate 对象,这个自动配置的RedisTemplate就不会被实例化。
【注意:正如此章节(1)(2)中自定义的redisTemplate方法名一定要叫“redisTemplate ”,因为@Bean注解是根据“方法名”配置这个bean的name的。此时达到覆盖默认配置的目地】
【例】 配置一个RredisTemplate
配置一个泛型为<String,Object>形式的RedisTemplate。
设置这个RedisTemplate把数据存入Redis时key-value的序列化方式
(ps:默认使用的序列化方式是JdkSerializationRedisSerializer,用默认的这样的序列化方式,通过redis desktop manager查看存入的k-v时,显示的key-value不是正常字符)
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String,Object> template = new RedisTemplate <>();
template.setConnectionFactory(factory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
Redis 操作的工具类
/**
* redis 工具类
**/
@Component
public class RedisUtils {
/**
* 注入redisTemplate bean
*/
@Autowired
private RedisTemplate <String,Object> redisTemplate;
/**
* 指定缓存失效时间
*
* @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) {
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 void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(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) {
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);
}
// ================================Hash(哈希)=================================
/**
* 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) {
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);
}
// ============================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;
}
}
}