目录
Redis入门
Redis有16个数据库,默认使用的是第0个
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379[3]> dbsize #查看db大小!
(integer) 0
Redis-Key
- flushall 清除全部数据库
- flushdb 清除当前数据库
- keys * 查看所有的 key
- set key
- get key
- exits key 判断当前 key 是否存在
- move key 1 移动key 到数据库 1
- expire key 10 设置过期时间,单位是秒
- ttl key 查看key 的剩余时间
- type key 查看 key 的类型
五大数据类型
String
append key abc #给 key 追加一个字符串 当 key 不存在就set
strlen key #获取字符串长度
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增 1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自减 1
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> INCRBY views 10 #设置步长 指定增量
(integer) 9
127.0.0.1:6379> INCRBY views 10
(integer) 19
127.0.0.1:6379> DECRBY views 5
(integer) 14
127.0.0.1:6379>
#字符串范围
127.0.0.1:6379> KEYS *
1) "views"
2) "name"
127.0.0.1:6379> GETRANGE name 0 2 #截取字符串 [0,2]
"yet"
127.0.0.1:6379> GETRANGE name 0 -1 #获取全部字符串
"yetong"
127.0.0.1:6379>
#替换
127.0.0.1:6379> SETRANGE name 1 ee #从指定位置开始字符替换
(integer) 6
127.0.0.1:6379> get name
"yeeong"
127.0.0.1:6379>
#setex(set with expire) 设置过期时间
127.0.0.1:6379> setex name2 30 yetong
OK
127.0.0.1:6379> ttl name2
(integer) 23
127.0.0.1:6379> get name2
"yetong"
127.0.0.1:6379>
#setnx(set if not exist)不存在=set ,存在的时候不执行任何操作(在分布式锁中常使用)
127.0.0.1:6379> setnx mykey yetong
(integer) 1
127.0.0.1:6379> KEYS *
1) "views"
2) "mykey"
3) "name"
127.0.0.1:6379> setnx mykey tomyee
(integer) 0
127.0.0.1:6379> get mykey
"yetong"
127.0.0.1:6379>
#批量操作
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> KEYS *
1) "k3"
2) "k1"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx 是一个原子性操作 要么都成功要么都失败
(integer) 0
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379>
#对象
#key 巧用冒号 对象:{id}:{属性}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 3
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "3"
127.0.0.1:6379>
#getset
#先 get 再 set
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mysql
"redis"
127.0.0.1:6379> get db
"mysql"
127.0.0.1:6379>
List
127.0.0.1:6379> LPUSH list one #将一个或者多个值插入到列表头部(左)
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> LRANGE list 0 1
1) "three"
2) "two"
127.0.0.1:6379> LPUSH list four five
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> RPUSH list zero #从右边插入一个值
(integer) 6
127.0.0.1:6379>
127.0.0.1:6379> LRANGE list 0 -1 #从左到右全部遍历
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
6) "zero"
#移除
127.0.0.1:6379> LRANGE list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
6) "zero"
127.0.0.1:6379> Lpop list #移除左边第一个
"five"
127.0.0.1:6379> LRANGE list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
5) "zero"
127.0.0.1:6379> RPOP list #移除右边第一个
"zero"
127.0.0.1:6379> LRANGE list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379>
#通过下标获取值
127.0.0.1:6379> LRANGE list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> LINDEX list 1
"three"
#获取数组长度
127.0.0.1:6379> Llen list
(integer) 4
#移除指定的值,精确匹配
lrem list 1 one 移除 list 里面的一个 one
lrem list 2 three 移除 list 里面的两个 three
#ltrim 裁剪
ltrim list 1 2 #截取指定长度,list已经改变了,只剩下截取的长度了
rpoolpush
#移除列表最左边元素并添加到新的列表
rpoplpush mylist myotherlist
lset list 0 item #第 0 位存在就更新为 item
linsert list before world hello #在 list 数组的 world 里面添加 hello
Set(集合)
set 中的值不能重复,无序
127.0.0.1:6379> sadd myset hello #添加元素
(integer) 1
127.0.0.1:6379> sadd myset world tomye
(integer) 2
127.0.0.1:6379> SMEMBERS myset #查看所有元素
1) "tomye"
2) "world"
3) "hello"
127.0.0.1:6379> SISMEMBER myset hello #查看是否存在元素
(integer) 1
127.0.0.1:6379> SISMEMBER myset yetong
(integer) 0
127.0.0.1:6379> SCARD myset #获取集合元素个数
(integer) 3
127.0.0.1:6379> SREM myset hello #移除元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "tomye"
2) "world"
127.0.0.1:6379> SRANDMEMBER myset #随机抽元素
"world"
127.0.0.1:6379> SRANDMEMBER myset
"world"
127.0.0.1:6379> SRANDMEMBER myset
"world"
127.0.0.1:6379> SRANDMEMBER myset
"tomye"
127.0.0.1:6379> SRANDMEMBER myset
"tomye"
127.0.0.1:6379> SRANDMEMBER myset 2#随机抽两个元素
1) "tomye"
2) "world"
127.0.0.1:6379> SPOP myset #随机移除一个
"world"
127.0.0.1:6379> SPOP myset 2 #随机移除两个
smove myset myset2 hello #移动元素到另外一个集合
sdiff myset1 myset2 #差集
sinter myset1 myset2 #交集
sunion myset1 myset2 #并集
Hash(哈希)
本质上和 String 类型一样,Key-Value 只不过这边的 value 也变成了 Key-Value 的形式
Key - value(key-value)
127.0.0.1:6379> hset myhash field1 tong #set 一个具体的 key-value
(integer) 1
127.0.0.1:6379> hget myhash field1
"tong"
127.0.0.1:6379> hmset myhash field1 hello field2 world #set 多个 key-value
OK
127.0.0.1:6379> hmget myhash field1 field2 #获取多个value
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash #获取全部
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> HDEL myhash field1 #删除 field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
127.0.0.1:6379> HLEN myhash #hash 长度
(integer) 1
127.0.0.1:6379> HEXISTS myhash field2 #判断某个字段是否存在
(integer) 1
127.0.0.1:6379> hkeys myhash #所有的 key
1) "field2"
2) "field1"
127.0.0.1:6379> HVALS myhash #所有的 value
1) "world"
2) "hello"
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1 #指定增量
(integer) 6
127.0.0.1:6379> HINCRBY myhash field3 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hell #不存在就设置
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 hell #存在不设置
(integer) 0
127.0.0.1:6379>
Zset(有序集合)
127.0.0.1:6379> ZADD myset 1 one #添加一个值
(integer) 1
127.0.0.1:6379> ZADD myset 2 two 3 three #添加多个值
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1 # 查看全部
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> ZADD salary 500 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 1000 lisi 2000 wangwu
(integer) 2
127.0.0.1:6379> zrangebyScore salary -inf +inf #升序排序
1) "zhangsan"
2) "lisi"
3) "wangwu"
127.0.0.1:6379> zrangebyScore salary -inf +inf withscores #升序排序并显示值
1) "zhangsan"
2) "500"
3) "lisi"
4) "1000"
5) "wangwu"
6) "2000"
127.0.0.1:6379> zrangebyScore salary -inf 1000 withscores #小于等于 1000带值显示
1) "zhangsan"
2) "500"
3) "lisi"
4) "1000"
127.0.0.1:6379> ZREM salary lisi #移除lisi
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1
1) "zhangsan"
2) "wangwu"
127.0.0.1:6379> ZRANGE salary 0 -1 withscores
1) "zhangsan"
2) "500"
3) "wangwu"
4) "2000"
127.0.0.1:6379> ZCARD salary #获取集合中的元素个数
(integer) 2
127.0.0.1:6379> ZCOUNT salary 1 2000 #获取【1,200】中的个数
(integer) 2
三种特殊数据类型
Geospatial地理位置
Redis 的 GEO 特性在 3.2 版本中推出, 这个功能可以将用户给定的地理位置信息储存起来。
通常用以实现诸如附近位置、摇一摇这类依赖于地理位置信息的功能。
geo 的数据类型为 zset。
GEO 的数据结构总共有六个常用命令:
geoadd
、geopos
、geodist
、georadius
、georadiusbymember
、gethash
geoadd
-
geoadd
命令以标准的x,y格式接受参数,所以用户必须先输入经度,然后再输入纬度。 -
geoadd
能够记录的坐标是有限的:非常接近两极的区域无法被索引。 -
有效的经度介于 -180 ~ 180 度之间,有效的纬度介于 -85.05112878 ~ 85.05112878 度之间。当输入超出范围的经度或者纬度,
geoadd
将返回一个错误。
geopos
- 从 key 里返回所有给定位置元素的位置(经度和纬度)
geodist
-
返回两个给定位置之间的距离,如果两个位置之间的其中一个不存在,那么命令返回空值。
-
指定单位的参数 unit 必须是以下单位的其中一个:
- m 表示单位为米
- km 表示单位为千米
- mi 表示单位为英里
- ft 表示单位为英尺
-
如果用户没有显式地指定单位参数,那么
geodist
默认使用米作为单位。 -
geodist
在计算距离时会假设地球为完美的球形,在极限情况下,这一假设最大会造成 0.5% 的误差。
georadius
- 以给定的经纬度为中心,找出某一半径内的元素。
georadiusbymember
- 找出位于指定范围内的元素,中心点是由给定的位置元素决定
geohash
- 将二维经纬度转换为一维字符串,字符串越长表示位置更精确,两个字符串越相似表示距离越近。
zrem
- GEO 没有提供删除成员的命令,但是因为 GEO 的底层实现是 zset,所以可以借用
zrem
命令实现对地理位置信息的删除。
原文链接:https://www.kuangstudy.com/bbs/1526414199528763393
HyperLogLog基数统计
其优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的,并且是很小的。
每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2 ^ 64 个不同元素的基数。
HyperLogLog 是一种算法,它提供了不精确的去重计数方案。
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8},基数(不重复元素)为 5。
基数估计就是在误差可接受的范围内,快速计算基数。
pfadd
添加
pfcount
统计获取基数
pfmerge
A,B合并成 C后统计基数
原文链接:https://www.kuangstudy.com/bbs/1529017995744391170
BitMap位图
当需要统计用户一年的某些信息,如活跃或不活跃,登录或不登录,打卡或没打卡。
如果使用普通的 key / value存储,则要记录 365 条记录,如果用户量很大,需要的空间也会很大。
Redis 提供了 Bitmap 位图这种数据结构,Bitmap 就是通过操作二进制位来进行记录,即为 0 和 1。
如果要记录 365 天的打卡情况,使用 Bitmap 表示的形式大概如下:0101000111000111……
这样 365 天相当于 365 bit,又 1 字节 = 8 bit , 所以相当于使用 46 个字节即可。
BitMap 就是通过一个 bit 位来表示某个元素对应的值或者状态,其中的 key 就是对应元素本身。
实际上底层也是通过对字符串的操作来实现的。
setbit
添加
getbit
单项取值
bitcount
统计 key 上,位为 1 的个数
原文链接:https://www.kuangstudy.com/bbs/1529023625540546562
事务
Redis 单条命令具有原子性,事务不保证原子性!
一次性
、顺序性
、排他性
, 执行一系列命令
Redis事务:
- 开启事务(multi)
- 命令入队
- 执行事务(exec)
- 放弃事务(discard)
编译型异常(例如入队的时候就报语法错误),那么整个事务都会被回滚,都不执行
运行时异常(代码语法没有问题,比如(1/0)),那么其他语句会正常执行,错误语句抛出异常不执行
乐观锁
watch
事务开始之前先 watch 该 key(简单理解成事务开始前先获取 version),然后执行事务(比较 version,一致就成功)。
如果事务执行失败了,就 unwatch,重新watch最新的(version)。
Jedis
基本使用
-
导入 Jedis 依赖
-
Jedis jedis = new Jedis(ip,端口) jedis.apiAPI 和上面 Redis 所有命令都保持一致! jedis.close()
事务
注意 try catch 包裹