Redis--狂神说Redis基础汇总(完结)
Redis--狂神说Redis基础汇总(完结)
2021.6.12-2021.6.14:端午学学玩玩弄完了Redis基础的汇总,越学越觉得自己知识量的匮乏。
参考链接:狂神说Java--Redis汇总:https://www.bilibili.com/video/BV1S54y1R7SB?p=1
Redis五种基本数据类型:
1.String字符串
OK
127.0.0.1:6380> set k1 1
OK
127.0.0.1:6380> INCR k1
2
127.0.0.1:6380> DECR k1
1
127.0.0.1:6380> keys *
k1
127.0.0.1:6380> set k2 huyuqiao
OK
127.0.0.1:6380> GETRANGE K2 0 3 127.0.0.1:6380> GETRANGE k2 0 3
huyu
127.0.0.1:6380> GETRANGE k2 0 -1
huyuqiao
127.0.0.1:6380> SETRANGE k2 1 XX
8
127.0.0.1:6380> get k2
hXXuqiao
127.0.0.1:6380> SETEX k3 30 "hello, world" #set exist:存在或不存在都替换
OK
127.0.0.1:6380> ttl k3
28
127.0.0.1:6380> ttl k2
-1
127.0.0.1:6380> keys *
k1
k2
127.0.0.1:6380> ttl k3
-2
127.0.0.1:6380> setnx mykey "redis" #set if not exist:不存在就set,存在就set失败,还是原来值
1
127.0.0.1:6380> ttl mykey
-1
127.0.0.1:6380> setnx mykey "mongodb"
0
127.0.0.1:6380> get mykey
redis
127.0.0.1:6380> ttl k2 #永久返回-1
-1
127.0.0.1:6380> ttl k3 #过期返回-2
-2
127.0.0.1:6380>
127.0.0.1:6380> mset user:1:name huyuqiao user:1:age 22
OK
127.0.0.1:6380> mget user:1:name user:1:age
huyuqiao
22
127.0.0.1:6380>List
127.0.0.1:6380> FLUSHALL
OK
127.0.0.1:6380> clear
127.0.0.1:6380> LPUSH list 1
1
127.0.0.1:6380> LPUSH list 2
2
127.0.0.1:6380> LPUSH list 3
3
127.0.0.1:6380> LRANGE list 0 -1
3
2
1
127.0.0.1:6380> RPUSH list a
4
127.0.0.1:6380> LPOP list
3
127.0.0.1:6380> LRANGE 0 -1
ERR wrong number of arguments for 'lrange' command 127.0.0.1:6380> LRANGE list 0 -1
2
1
a
127.0.0.1:6380> LINDEX list 0
2
127.0.0.1:6380> LLEN list
3
127.0.0.1:6380> FLUSHALL
OK
127.0.0.1:6380> clear
127.0.0.1:6380> LPUSH list one
1
127.0.0.1:6380> LPUSH list two
2
127.0.0.1:6380> LPUSH list two
3
127.0.0.1:6380> LREM list 1 one #移除list中等于one的一个元素(最后加入的移除掉)
1
127.0.0.1:6380> LRANGE list 0 -1
two
two
127.0.0.1:6380> LREM list 2 one
0
127.0.0.1:6380> LREM list 2 two
2
127.0.0.1:6380> LRANGE list 0 -1 127.0.0.1:6380> FLUSHALL 127.0.0.1:6380> LPUSH list one
1
127.0.0.1:6380> LPUSH list two
2
127.0.0.1:6380> LPUSH list three
3
127.0.0.1:6380> LPUSH list four
4
127.0.0.1:6380> LTRIM list 1 2
OK
127.0.0.1:6380> LRANGE list 0 -1
three
two
127.0.0.1:6380>Set
127.0.0.1:6380> FLUSHALL
OK
127.0.0.1:6380> SADD myset "hello"
1
127.0.0.1:6380> sadd myset "world"
1
127.0.0.1:6380> sadd myset "huyuqiao"
1
127.0.0.1:6380> smembers myset
hello
huyuqiao
world
127.0.0.1:6380> SISMEMBER myset huyuqiao
1
127.0.0.1:6380> sadd myset "HYQ"
1
127.0.0.1:6380> SMEMBERS myset
hello
huyuqiao
HYQ
world
127.0.0.1:6380> SREM myset hello
1
127.0.0.1:6380> scard myset
3
127.0.0.1:6380> SMEMBERS myset
huyuqiao
HYQ
world
127.0.0.1:6380> SRANDMEMBER myset
world
127.0.0.1:6380> SRANDMEMBER myset
huyuqiao
127.0.0.1:6380>
Hash
huyuqiao
127.0.0.1:6380> FLUSHALL
OK
127.0.0.1:6380> clear
127.0.0.1:6380> hset myhash field1 huyuqiao
1
127.0.0.1:6380> hmset myhash field1 hello field2 world
OK
127.0.0.1:6380> hmget myhash field1 field2
hello
world
127.0.0.1:6380> hgetall myhash
field1
hello
field2
world
127.0.0.1:6380> hlen myhash
2
127.0.0.1:6380> HEXISTS myhash field1
1 127.0.0.1:6380> HKEYS myhash
field1
field2
127.0.0.1:6380> HVALS myhash
hello
world
127.0.0.1:6380> HSETNX myhash field4 hello #hash设置
1
127.0.0.1:6380> HGETALL myhash
field1
hello
field2
world
field4
hello
127.0.0.1:6380>
Zset
127.0.0.1:6380> zadd salary 100 huyuqiao
1
127.0.0.1:6380> zadd salary 200 HUYUQIAO
1
127.0.0.1:6380> zadd salary 300 HYQ
1
127.0.0.1:6380> ZRANGEBYSCORE salary -inf +inf
huyuqiao
HUYUQIAO
HYQ
127.0.0.1:6380> zrange salary 0 -1
huyuqiao
HUYUQIAO
HYQ
127.0.0.1:6380> zrem salary huyuqiao
1
127.0.0.1:6380> ZRANGEBYSCORE salary -inf +inf
HUYUQIAO
HYQ
Redis三种特殊数据类型:
1.GeoSpatical
适用场景:获取附近人,好友距离,网约车定位功能。
# 添加位置经纬度
127.0.0.1:6379> GEOADD china:city 116.41667 39.91667 北京
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.43333 31.23000 上海
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.45000 29.56667 重庆
(integer) 1
127.0.0.1:6379> GEOADD china:city 114.06667 22.61667 深圳
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.20000 30.26667 杭州
(integer) 1
127.0.0.1:6379> GEOADD china:city 108.95000 34.26667 西安
(integer) 1
# 查看不同位置经纬度
127.0.0.1:6379> GEOPOS china:city 北京 西安
#查看不同位置之间距离(默认是m)
127.0.0.1:6379> GEODIST china:city 北京 上海
"1066981.1340"
127.0.0.1:6379> GEODIST china:city 北京 上海 km
"1066.9811"
127.0.0.1:6379> GEODIST china:city 北京 重庆 km
"1465.8918"
127.0.0.1:6379>
# 查看指定经纬度周边范围内的地方(可以以此扩散到周围指定范围内的指定人数的好友)
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
重庆
西安
深圳
杭州
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
重庆
西安
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist #查看某经纬度周围500km的所有城市和距离/km
重庆
346.0548
西安
484.7511
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord #查看某经纬度周围500km的所有城市和经纬度
重庆
106.4500012993812561
29.56666939001875249
西安
108.95000249147415161
34.2666710302806834
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km count 1 #查看某经纬度周围500km的三个城市
重庆
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km count 3 #查看某经纬度周围500km的三个城市
重庆
西安
127.0.0.1:6379>
#查看地点周边的所有城市(类似于定位)
127.0.0.1:6379> GEORADIUSBYMEMBER china:city 北京 1000 km
北京
西安
127.0.0.1:6379> GEORADIUSBYMEMBER china:city 上海 1000 km
杭州
上海
127.0.0.1:6379>
#将城市的二维经纬度转成一位hash字符串
127.0.0.1:6379> GEOHASH china:city 北京 重庆
wx4g14s53n0
wm78nq6w2f0
127.0.0.1:6379>
#GEO底层是zset,所有可以用zset命令来操作
127.0.0.1:6379> zrange china:city 0 -1 #查看所有城市
重庆
西安
深圳
杭州
上海
北京
127.0.0.1:6379> zrem china:city 北京 #删除北京这个城市
2.Hyperloglog
适用场景: 网站UV量。传统用set统计,但若存在大量用户id,则太消耗内容且麻烦,若只为计数且允许有错误率(0.81%),则可行,否则还是用set统计
基数:集合中不重复元素个数。如{1, 3, 5, 5 ,7}则为{1,3,5,7},基数为4
127.0.0.1:6379> clear
127.0.0.1:6379> PFADD mykey a b c d e f g h i j #设置mykey 集合
(integer) 1
127.0.0.1:6379> PFCOUNT mykey #统计mykey 集合基数数量
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 #2个集合取并集
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15
127.0.0.1:6379>
3.Bitmaps
适用场景:判断、统计活跃、不活跃,登录、未登录这些非1即0的场景
[root@VM-8-11-centos ~]# redis-cli -a root --raw
127.0.0.1:6379> setbit sign 0 1 #设置sign用户某天是否打卡
(integer) 0
127.0.0.1:6379> SETBIT sign 1 0
(integer) 0
127.0.0.1:6379> SETBIT sign 2 0
(integer) 0
127.0.0.1:6379> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379> SETBIT sign 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign 5 0
(integer) 0
127.0.0.1:6379> SETBIT sign 6 0
(integer) 0
127.0.0.1:6379> GETBIT sign 3 #得到sign用户某天打卡情况
(integer) 1
127.0.0.1:6379> GETBIT sign 6
Redis事务:
Reidsi事务:没有隔离级别概念,即事务不保证原子性(事务内部有多条命令,不一定,可以实现部分成功、部分失败),但是单条命令保证原子性
1.Redis事务流程:
- 开启事务(multi)
- 命令入队
- 执行事务(exec)
#开启-结束事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
OK
OK
v2
OK
127.0.0.1:6379>
#放弃事务:之前队列代码全部rollback
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 asdfasdf
QUEUED
127.0.0.1:6379> DISCARD
OK
127.0.0.1:6379> EXEC
ERR EXEC without MULTI
127.0.0.1:6379> get k2
v2
2.Redis事务非原子性
之所以事务非原子性,是因为有两种异常:
编译性异常(检查性异常):代码错了,根本就没某个语句、函数、配置文件等
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> gasdfa k3 #语句错误,相当于没执行,在编译时候就出错了
ERR unknown command 'gasdfa' 127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> EXEC
EXECABORT Transaction discarded because of previous errors. 127.0.0.1:6379> get k4 127.0.0.1:6379> get k1运行时异常(非检查性异常):没有某个变量、某个对象没有new等(不会全部rollback)
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> EXEC
ERR value is not an integer or out of range OK
v2 #上面出错了,但是依然不影响下面语句执行,所以证明了redis事务是不保证原子性的
127.0.0.1:6379>
Redis乐观锁:
乐观锁:不会上锁,更新数据时才会比较version是否被人修改过(redis事务中如果被修改过,则事务不会执行成功)
悲观锁:无论做什么,都会上锁,效率低下但是安全
Redis事务中用<font color=red size=3>Watch</font>
实现乐观锁,中途如果被修改,导致version变更,则事务全部都不会成功
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money #Redis乐观锁:watch监视money
OK
127.0.0.1:6379> MULTI #在另一个窗口将money改成了101
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> incrby out 10
QUEUED
127.0.0.1:6379> EXEC
127.0.0.1:6379> get money
101
127.0.0.1:6379>
SpringBooot--配置Redis源代码
Jedis:直连,多线程下不安全,类似于BIO模式(Springboot2.X后被淘汰)
Lettuce:采用Netty,多线程下共享,类似于NIO模式
autoconfig->srping.factories中找到redis相关配置
@Configuration(proxyBeanMethods = false)
@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;
}
}
SpringBooot--自定义RedisTemplate、RedisUtil
1.RedisTemplate序列化配置
package com.empirefree.springboot.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
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;
/**
* @program: springboot
* @description: RedisTemplate配置
* @author: huyuqiao
* @create: 2021/06/13 16:05
*/
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.WRAPPER_ARRAY);
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 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;
}
}
2.RedisUtil配置(CRUD操作string,map,list,set)
package com.empirefree.springboot.utils;
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.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @program: springboot
* @description: Redis工具类
* @author: huyuqiao
* @create: 2021/06/13 16:14
*/
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// =============================common============================
/**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
*/
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((Collection<String>) 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)
*/
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)
*/
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
*/
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 对应多个键值
*/
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)
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
* @param key 键
*/
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 键
*/
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代表所有值
*/
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 键
*/
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倒数第二个元素,依次类推
*/
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 值
*/
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 时间(秒)
*/
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;
}
}
}
Redis--持久化
持久化:在指定时间间隔内将内存数据存入磁盘中,断电也能恢复数据,使用快照文件读到内存中。
1.Redis--RDB(默认推荐)
保存过程:父进程fork一个子进程,将数据持久化到临时文件中,持久化结束,再替换上次的RDB正式文件。
触发条件:
- save满足:命令
save 900 1
即是在15分钟内修改了1次 即会触发RDB。 - 执行FlushAll命令
- 退出Redis,会产生RDB文件
- save满足:命令
适用场景:适合大规模数据恢复且数据完整性不敏感的情况。
2.Redis--AOF(重启后是默认先载入AOF,因为数据更完整)
保存过程:父进程fork一个子进程,以日志形式将所有指令记录下来(读操作不记录),然后将数据只追加不改写到AOF文件,然后替换上次的AOF文件
触发条件:
appendfsync always/everysec/no
命令适用场景:对恢复数据完整性要求严格
重写场景:不断追加文件到一个阈值,则会重写aof文件
Redis--发布订阅
发布订阅:可以做消息推送、聊天室等等
#发布者:往Redis某渠道中发消息,所有订阅者都可以接收到
127.0.0.1:6379> PUBLISH huyuqiao "hello,world"
1
#订阅者:订阅Redis中某个渠道channel
127.0.0.1:6379> SUBSCRIBE huyuqiao
subscribe
huyuqiao
1
message
huyuqiao
hello,world
Redis--主从复制(主写从读)
1.Linux配置文件
- daemonize的no改成yes
- port、pidfile、logfile、dbfilename改成对于新redis名
- 如果redis有密码,需要在slave中配置或者在master中去掉密码
#master断了,slaver依然是原来master的slaver。但是slaver断了,master就没有slaver了
>>slaveof no one #关闭slave状态,变成master
>>shutdown #停止redis,其slave状态停止,下次启动变成master,且原来master下的该redis就没有了
redis-server redis80.conf #启动80redis窗口。
kill -s 9 pid #关闭某个进程
2. 复制原理
- 全量复制:slave启动后,发送sync同步命令给master,然后同步master中所有数据
- 增量复制:master写数据后,slave实时得到。
Redis--哨兵模式
流程:如下,在启动哨兵后,关闭79主服务,就从80,81中投票选举了80为主服务,然后把79,80都当成了slave,所以下次79启动的时候会默认是slave。另外,由于数据是增量复制,所以数据在80中保存完好,且79启动后就全量复制到79中了
#哨兵模式下的日志
8044:X 14 Jun 16:35:06.885 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
8044:X 14 Jun 16:35:06.885 # Sentinel ID is c0ce22fc8365ff48663b7db710ce8c359529c3d9
8044:X 14 Jun 16:35:06.885 # +monitor master mymaster 127.0.0.1 6379 quorum 1
8044:X 14 Jun 16:35:51.556 # +sdown master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.556 # +odown master mymaster 127.0.0.1 6379 #quorum 1/1
8044:X 14 Jun 16:35:51.556 # +new-epoch 1
8044:X 14 Jun 16:35:51.556 # +try-failover master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.572 # +vote-for-leader c0ce22fc8365ff48663b7db710ce8c359529c3d9 1
8044:X 14 Jun 16:35:51.572 # +elected-leader master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.572 # +failover-state-select-slave master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.624 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.624 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.684 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.826 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.826 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:51.914 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:52.831 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:52.831 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:52.912 # +failover-end master mymaster 127.0.0.1 6379
8044:X 14 Jun 16:35:52.912 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
8044:X 14 Jun 16:35:52.912 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
8044:X 14 Jun 16:35:52.912 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
Redis--缓存穿透、击穿、雪崩
- 缓存穿透:缓存和数据库中都没有数据
- 解决方案:1.布隆过滤器 2.存储空对象:数据库没找到后,redis中临时存一个空对象
- 缓存击穿:某个key值过期,来了大量访问
- 解决方案:1.永不过期 2.分布式锁:一个线程获取,其他线程等待
- 缓存雪崩:海量key值过期,来了大量访问
- 解决方案:1.redis高可用:多设置几台redis 2.限流降级:缓存失效后,通过加锁或者队列来控制读数据库写缓存的数量 3.数据预热:大量数据加载到缓存中,根据不同访问量来设置不同过期时间
Redis--狂神说Redis基础汇总(完结)的更多相关文章
- redis基础:redis下载安装与配置,redis数据类型使用,redis常用指令,jedis使用,RDB和AOF持久化
知识点梳理 课堂讲义 课程计划 1. REDIS 入 门 (了解) (操作) 2. 数据类型 (重点) (操作) (理解) 3. 常用指令 (操作) 4. Jedis (重点) (操作) ...
- Redis(一)基础数据结构
1.目录 Redis 基础数据结构 string (字符串) list (列表) hash (字典) set (集合) zset (集合) 容器型数据结构的通用规则 过期时间 2.Redis 基础数据 ...
- springboot配置redis+jedis,支持基础redis,并实现jedis GEO地图功能
Springboot配置redis+jedis,已在项目中测试并成功运行,支持基础redis操作,并通过jedis做了redis GEO地图的java实现,GEO支持存储地理位置信息来实现诸如附近的人 ...
- 狂神说redis笔记(三)
八.Redis.conf 容量单位不区分大小写,G和GB有区别 可以使用 include 组合多个配置问题 网络配置 日志 # 日志 # Specify the server verbosity le ...
- redis从0-1学习记录(完结)
1. NoSQL(not only sql):不仅仅是数据库,非关系型数据库,关系型数据库是以表格的行列进行存储的,而非关系型数据库是以键值对进行存储,不需要固定的格式.非关系型数据库的特点,方便扩展 ...
- Redis基本认识和基础学习-基本命令
Redis 基本介绍 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANS ...
- Redis服务搭建与基础功能示例
一.Redis简介 Redis是一个非关系型远程内存数据库,它也是一个Key-value模型的数据库.Redis支持5种数据类型(string.list.set.sorted set.hash),可以 ...
- Redis源码研究—基础知识
1. Redis 是什么 Redis是一个开源的使用ANSI C语言编写的基于内存的key/value存储系统,与memcache类似,但它支持的value类型更多,包括:字符串(string).链表 ...
- Redis学习笔记之基础篇
Redis是一款开源的日志型key-value数据库,目前主要用作缓存服务器使用. Redis官方并没有提供windows版本的服务器,不过微软官方开发了基于Windows的Redis服务器Micro ...
随机推荐
- jupyter中那些神奇的第三方拓展魔术命令
1 简介 无论是jupyter notebook还是jupyter lab,都可以使用ipython中的众多自带魔术命令来实现丰富的辅助功能,诸如%time之类的. 这些都已经是老生常谈的知识没什么好 ...
- .NET Core 中依赖注入框架详解 Autofac
本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的 Autofac相比.NET Core原生的注入方式提供了强大的功能, ...
- ThreadLocal引起的一次线上事故
> 线上用户存储数据后查看提示无权限 前言 不知道什么时候年轻的我曾一度认为Java没啥难度,没有我实现不了的需求,没有我解不了的bug 直到我遇到至今难忘的一个bug . 线上用户存储数据后查 ...
- 『居善地』接口测试 — 4、Requests库发送GET请求
目录 1.使用Requests库发送带参数的GET请求 2.查看GET请求的内容 3.带请求头.参数的Get请求 Requests库GET请求是使用HTTP协议中的GET请求方式对目标网站发起请求. ...
- QFNU-11.08training
7-1 阅览室 题目: 天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者借书时,管理员输入书号并按下S键,程序开始计时:当读者还书时,管理员输入书号并按下E键,程序结束计时.书号为不超过10 ...
- .Net Core·热加载的实现及测试
阅文时长 | 0.25分钟 字数统计 | 460字符 主要内容 | 1.引言&背景 2.解决原理&方法 3.声明与参考资料 『.Net Core·热加载的实现及测试』 编写人 | SC ...
- Powershell阻止确认
要阻止弹出确认提示,需要设置-Confirm为false, new-VM -Name $hostname -Template $template -VMHost 10.11.31.5 -OSCusto ...
- Linux查看PCIe版本及速率# lspci -vvv |grep Width -i
Linux查看PCIe版本及速率 https://www.cnblogs.com/lsgxeva/p/9542975.html# lspci -vvv |grep Width -i # lspci | ...
- 【转载】有图 KVM折腾记..
KVM折腾记...https://lengjibo.github.io/KVM%E6%8A%98%E8%85%BE%E8%AE%B0/ Veröffentlicht am 2018-09-20 | ...
- TCP/IP协议三次握手_四次挥手
TCP/IP协议 TCP是一种面向连接的端到端的可靠传输协议. TCP报头格式 三次握手的过程 一.客户端发送一个连接请求,发送一个随机数X,这时客户端的端口状态变为SYN_SENT状态. 二.服务端 ...