Redis入门
一、压力测试
- 命令
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000
- 指令大全
二、基本指令
- 进入客户端:
redis-cli
- 切换数据库
select 1(0~16)
- 清空当前数据库
flushdb
- 清空所有数据库数据
flushall
- 查看当前库所有的key
key *
- 插入/修改
get [key] / set [key] [value]
- 当前库数据条目
dbsize
- 是否存在key
exists [key]
- 移动key / 移除key
move [key] 1 / del [key]
- k-v 的类型
type
- 获取修改
getset
过期时间
- 设置过期时间
expire [k] [time]
ttl key
- 过期时间
setex [k] [time] [v]
- 分布式锁
SETNX [k] [v]
- 批量设置k-v
MSET k1 v1 k2 v2 k3 v3
- 批量获取
MGET k1 k2 k3
- 批量分布式
MSETNX
三、五大数据类型
1、String
- 追加字符串
append [k] [v]
- 截取字符串
getrange [key] [start] [end]
- 修改字符串
SETRANGE [key] [offset] [value]
- +1
incr [key]
- -1
decr [key]
- 自定义加减
INCRBY [key] [自增数]
2、List
- 头插
lPUSH [key] [values…]
- 尾插
RPUSH [key] [values…]
- 头弹出
LPOP [key]
- 尾弹出
RPOP [key]
- 取所有值
LRANGE [key] 0 -1
- 下标取值
LINDEX [key] [index]
- list长度
LLEN [key]
- 删除指定的值
LREM [key] [count] [value]
- 取出l1尾值放到l2头部
RPOPLPUSH l1 l2
3、Set
- 无需不重复集合
- 添加元素
SADD [key] [member…]
- 查看所有值
SMEMBERS [key]
- 判断是否在某个集合中
SISMEMBER [key] [member]
- 获取集合长度
SCARD [key]
- 移除指定元素
SREM [key] [member]
- 随机抽选元素
SRANDMEMBER [key] [count]
- 差集
SDIFF [key1] [key2] …
- 交集
SINTER [key1] [key2] …
- 并集
SUNION [key1] [key2] …
4、Hash
- set
HSET [key] [field] [value]
- get
HGET [key] [field] [value]
- 设置多个值
HMSET [key] f1 v1 f2 v2 f3 v3
- 获取所有k-v
HGETALL [key]
- 删除
HDEL [key] [field]
- hash长度
HLEN [key]
- 判断是否存在
HEXISTS [key] [field]
127.0.0.1:6379[2]> HEXISTS myhash g
(integer) 0
127.0.0.1:6379[2]> HEXISTS myhash a
(integer) 1
5、Zset
- 有序的集合
- 添加元素
// score下标
set [key] [score] [value]
- 排序 按照score排序
ZRANGEBYSCORE myset2 -inf +inf
四、三种特殊数据类型
1、geospatial 地理位置
- 基本命令
GEOADD
GEODIST
GEOHASH
GEOPOS
GEORADIUS
GEORADIUSBYMEMBER
- GEOADD (设置)
命令:
GEOADD [key] [精度] [纬度] [member]
例子:
GEOADD [key] [精度] [纬度] [member]
127.0.0.1:6379[1]> GEOADD china:city 121.48 31.22 shanghai
(integer) 1
127.0.0.1:6379[1]> GEOADD china:city 102.73 25.04 yunan
(integer) 1
127.0.0.1:6379[1]> GEOADD china:city 104.06 30.67 sichuan
(integer) 1
- GEOPOS (取值)
命令:
127.0.0.1:6379[1]> GEOPOS china:city shanghai
1) 1) "121.48000091314315796"
2) "31.21999956478423854"
- GEODIST(返回两个坐标距离)
参数unit:
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。
命令:
GEODIST key member1 member2 [单位unit]
例:
127.0.0.1:6379[1]> GEODIST china:city shanghai yunan km
"1960.1311"
- GEORADIUS (返回半径之内的所有位置元素)
命令:
GEORADIUS [key] [longitude] [latitude] [radius 半径] [m|km|ft|mi] [withdist 直线距离] [withcoord 经纬度] [count 1 指定查询数量]
例:
127.0.0.1:6379[1]> GEORADIUS china:city 121 31 100 km withdist withcoord count 1
1) 1) "shanghai"
2) "51.8477"
3) 1) "121.48000091314315796"
2) "31.21999956478423854"
- GEORADIUSBYMEMBER (指定位置决定)
命令:
GEORADIUSBYMEMBER china:city shanghai 1000 km
例子:
127.0.0.1:6379[1]> GEORADIUSBYMEMBER china:city shanghai 1000 km
1) "shanghai"
2) "sh-songjiang"
2、hyperloglogs 基数统计
- 基数 (不重复的元素)
# 添加
127.0.0.1:6379[1]> PFADD mypf d sad d d da d d d ad as
(integer) 1
# 不重复元素数量
127.0.0.1:6379[1]> PFCOUNT mypf
(integer) 5
# 合并两个集合
127.0.0.1:6379[1]> PFMERGE mypf3 mypf mypf2
OK
3、bitmaps
- 位存储 (二进制进行记录 0101010)
- 记录一周的打卡情况
# 周一:0 周二:1 周三:1 周四:0 ......
# setbit
127.0.0.1:6379[1]> SETBIT sign 1 0
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 2 1
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 4 0
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 5 1
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 6 1
(integer) 0
127.0.0.1:6379[1]> SETBIT sign 7 0
(integer) 0
# gitbit
127.0.0.1:6379[1]> GETBIT sign 1
(integer) 0
# bitcount 统计打卡记录
127.0.0.1:6379[1]> BITCOUNT sign
(integer) 4
五、事务
事务的基本操作
- 开启事务(multi)
- 事物入队
127.0.0.1:6379[1]> MULTI # 开启事物
OK
127.0.0.1:6379[1]> HSET myset f1 v1 # 入队
QUEUED
127.0.0.1:6379[1]> HSET myset f2 v2 # 入队
QUEUED
127.0.0.1:6379[1]> EXEC # 执行入队的命令
1) (integer) 1
2) (integer) 1
- 执行事务(exec)
- 放弃事务(discard)
事务实现-乐观锁、悲观锁
- 悲观锁(认为任何操作都会出错,无论做什么都加锁)
- 乐观锁(认为任何操作都不会出错,只在跟新数据时候判断是否有人修改过这个数据)
# 监视这个key,在exec是否发生其他变化,发生变化执行失败
127.0.0.1:6379> WATCH money
OK
# exec和discard也可以解锁
# 放弃当前的锁,,,,重新建一个锁,,,执行之后操作
127.0.0.1:6379> UNWATCH
OK
六、SpringBoot整合
- application.yml 配置连接参数:
## Redis 配置
spring:
redis:
# database: 0 #数据库索引(默认为0)
host: 127.0.0.1
port: 6379 #默认链接端口
password: #默认为空
lettuce:
pool:
max-active: 20 #最大链接池
max-wait: -1 #最大阻赛等待时间(使用负值没有限制)默认为-1
max-idle: 20 #连接池中的最大空闲连接 默认 8
min-idle: 0
- 自定义RedisConfig(由于redis的原生配置不支持序列化,所以需要手动配置config的template模版完善序列化操作)
/**
* @since 2020/9/10 20:01
*/
//配置类的注解
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* retemplate相关配置
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
System.out.println("11");
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// value采用json序列化
template.setValueSerializer(jacksonSeial);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
return template;
}
/**
* 对hash类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}
/**
* 对redis字符串类型数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}
/**
* 对链表类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}
/**
* 对无序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}
/**
* 对有序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}
- 配置RedisUtil
/**
* @since 2020/9/11 23:02
*/
@Component
public final class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// =============================common============================
/**
* 指定缓存失效时间
*
* @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 );
}
// ================================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 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;
}
}
}