Java && Redis(RedisAPI 包括setNx分布式锁的简单实现)

中文文档 点击跳转.

一:基本命令

1.连接 redis

redis-cli  -p ****  -h ***.***.***.***  -a ******

-p + 端口号  -h + IP  -a + 密码

 输入ping 测试连接成功 #查看当前连接是否正常,正常返回PONG

2.简单介绍一下Redis中队Key的操作命令。最常用的命令!

[root@node1 ~]# redis-cli -p 7006 -h 192.168.51.174 -a *****  #登录
192.168.51.174:7006> ping   #测试连接
PONG    #连接成功
192.168.51.174:7006> keys * #获取所有key
(empty array)
192.168.51.174:7006> flushall  # 清空所有数据库的键值对  flushdb:清空当前数据库中的键值对。
OK
192.168.51.174:7006> set name test  # 设置一个key为name,值为test的数据
OK
192.168.51.174:7006> get name   # 根据key拿值
"test"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> set keyname  keyvalue
OK
192.168.51.174:7006> keys *
1) "keyname"
192.168.51.174:7006> get keyname
"keyvalue"
192.168.51.174:7006> exists keyname  #是否存在这个key
(integer) 1
192.168.51.174:7006> get kname
"kvalue"
192.168.51.174:7006> set kname1 kvalue1
OK
192.168.51.174:7006> keys *
1) "kname1"
2) "kname"
192.168.51.174:7006> MOVE kname1 1   # 删除当前库1的key为'kname1'的数据
(integer) 1
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> set kname kvalue
OK
192.168.51.174:7006> EXPIRE kname 20  #设置20秒超时
(integer) 1
192.168.51.174:7006> ttl kname
(integer) 16
192.168.51.174:7006> ttl kname
(integer) 10
192.168.51.174:7006> ttl kname
(integer) 8
192.168.51.174:7006> ttl kname
(integer) 6
192.168.51.174:7006> ttl kname
(integer) 1
192.168.51.174:7006> ttl kname
(integer) 0
192.168.51.174:7006> ttl kname
(integer) -2
192.168.51.174:7006> ttl kname
(integer) -2
192.168.51.174:7006> 

二:Redis的五大数据类型

1.String类型

String是Redis中最常用的一种数据类型,也是Redis中最简单的一种数据类型。首先,表面上它是字符串,但其实他可以灵活的表示字符串、整数、浮点数3种值。Redis会自动的识别这3种值

192.168.51.174:7006> clear
192.168.51.174:7006> set kstr vstr  #设置数据,
#插入的数据中如果有空格的数据,请用""双引号或者用,隔开,否则会报错!
OK
192.168.51.174:7006> get kstr
"vstr"
192.168.51.174:7006> keys *
1) "kstr"
192.168.51.174:7006> EXISTS ksrt1  # 是否存在 不存在返回0
(integer) 0
192.168.51.174:7006> EXISTS kstr  # 存在返回1
(integer) 1
192.168.51.174:7006> APPEND kstr addRange   # 拼接字符串,并返回字符串长度
(integer) 12
192.168.51.174:7006> get kstr
"vstraddRange"
192.168.51.174:7006> strlen kstr  #获取字符串长度
(integer) 12
192.168.51.174:7006> set kstr kvalue
OK
192.168.51.174:7006> get kstr
"kvalue"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> set k 0  #创建一个数字类型数据
OK
192.168.51.174:7006> get k
"0"
192.168.51.174:7006> INCR k  # 自增,相当于java中 i++
(integer) 1
192.168.51.174:7006> get k
"1"
192.168.51.174:7006> get k
"1"
192.168.51.174:7006> INCR k
(integer) 2
192.168.51.174:7006> INCR k
(integer) 3
192.168.51.174:7006> get k
"3"
192.168.51.174:7006> INCRBY k 10   #指定数量自增
(integer) 13
192.168.51.174:7006> get k
"13"
192.168.51.174:7006> INCRBY k 5
(integer) 18
192.168.51.174:7006> DECR k        #自减
(integer) 17
192.168.51.174:7006> get k
"17"
192.168.51.174:7006> DECRBY k 7    # 指定数量自减
(integer) 10
192.168.51.174:7006> get k
"10"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> set k "hello,my love"
OK
192.168.51.174:7006> get k 
"hello,my love"
192.168.51.174:7006> GETRANGE k 6 13  #根据下标截取字符串
"my love"
192.168.51.174:7006> set k "hello,my love"
OK
192.168.51.174:7006> GETRANGE k 6 -1  #下标不能省略, -1代表到结尾
"my love"
192.168.51.174:7006> set k 1111111111111111111
OK
192.168.51.174:7006> get k 
"1111111111111111111"
192.168.51.174:7006> SETRANGE k 5 33333333  # 替换
(integer) 19
192.168.51.174:7006> get k
"1111133333333111111"
192.168.51.174:7006> EXPIRE k4 20  # 给不存在的key设置超时返回0
(integer) 0
192.168.51.174:7006> ttl k4        # -2即代表不存在
(integer) -2
192.168.51.174:7006> EXPIRE k 20   #设置超时成功返回1
(integer) 1
192.168.51.174:7006> ttl k         # 剩余14s超时
(integer) 14
192.168.51.174:7006> ttl k
(integer) 4
192.168.51.174:7006> ttl k
(integer) 1
192.168.51.174:7006> ttl k        # 已超时,不存在
(integer) -2
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> set k 1111111111111
OK
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> GETSET k 1111111111   #先获取,再赋值
(nil)
192.168.51.174:7006> get k
"1111111111"
192.168.51.174:7006> getset k 3434343433
"1111111111"
192.168.51.174:7006> get k
"3434343433"
192.168.51.174:7006> mset k1 v1 k2 2 k3 v3 k4 4   #批量设置
OK
192.168.51.174:7006> keys *
1) "k3"
2) "k4"
3) "k2"
4) "k1"
192.168.51.174:7006> mget k1 k2 k3 k4    #批量获取
1) "v1"
2) "2"
3) "v3"
4) "4"
192.168.51.174:7006> 

2.List(列表)

如果key 不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表,也代表不存在!
在两边插入或者改动值,效率最高! 中间元素相对来说效率会低一点

lpush(左插入)、lrange(查询集合)、rpush(右插入)

lpop(左移除)、rpop(右移除)

lindex(查询指定下标元素)、llen(获取集合长度) 

lrem(根据value移除指定的值)

ltrim(截取元素)、rpoplpush(移除指定集合中最后一个元素到一个新的集合中)

lset(更新)、linsert操作

192.168.51.174:7006> flushall
OK
192.168.51.174:7006> lpush k v1    #新增一个集合k 添加元素v1
(integer) 1
192.168.51.174:7006> lpush k v2    #添加元素v2
(integer) 2
192.168.51.174:7006> lpush k v3
(integer) 3
192.168.51.174:7006> lpush k v4
(integer) 4
192.168.51.174:7006> lpush k v5
(integer) 5
192.168.51.174:7006> lpush k v5
(integer) 6
192.168.51.174:7006> lpush k v5
(integer) 7
192.168.51.174:7006> lrange k 0 -1  # 查询所有元素 0是起始下标,-1是结束下标,
1) "v5"
2) "v5"
3) "v5"
4) "v4"
5) "v3"
6) "v2"
7) "v1"
192.168.51.174:7006> lpush k1 v1 v2 v3 v4 v5 v5 v5 v5  #批量添加
(integer) 8
192.168.51.174:7006> lrange k1 0 -1    #查询集合所有元素
1) "v5"
2) "v5"
3) "v5"
4) "v5"
5) "v4"
6) "v3"
7) "v2"
8) "v1"
192.168.51.174:7006> llen k  # 获取长度
(integer) 8
192.168.51.174:7006> lindex k 0   #根据下标获取元素
"v5"
192.168.51.174:7006> lindex k 4   #根据下标获取元素
"v3"
192.168.51.174:7006> lrange k 0 0  #指定元素查询
1) "v5"
192.168.51.174:7006> lrange k 0 4  #指定范围获取
1) "v5"
2) "v5"
3) "v5"
4) "v4"
5) "v3"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> lpush k v1 v2 v3 v4 v5
(integer) 5
192.168.51.174:7006> rpush k1 v1 v2 v3 v4 v5  #右插入,从集合末尾插入 方向与lpush相反
(integer) 5
192.168.51.174:7006> lrange k 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
192.168.51.174:7006> lrange k1 0 -1
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> lpush k v0 v1 v2 v3 v4 v5 v6 v7 v8 v9
(integer) 10
192.168.51.174:7006> lrange k 0 -1
 1) "v9"
 2) "v8"
 3) "v7"
 4) "v6"
 5) "v5"
 6) "v4"
 7) "v3"
 8) "v2"
 9) "v1"
10) "v0"
192.168.51.174:7006> lpop k     #返回第一个元素并移除
"v9"
192.168.51.174:7006> lpop k 2   #移除前两个元素
1) "v8"
2) "v7"
192.168.51.174:7006> lrange k 0 -1
1) "v6"
2) "v5"
3) "v4"
4) "v3"
5) "v2"
6) "v1"
7) "v0"
192.168.51.174:7006> rpop k    #移除最后一个元素
"v0"
192.168.51.174:7006> rpop k 3  # 移除后三个元素
1) "v1"
2) "v2"
3) "v3"
192.168.51.174:7006> lrange k 0 -1
1) "v6"
2) "v5"
3) "v4"
192.168.51.174:7006> lrange k 0 -1
1) "v6"
2) "v5"
3) "v4"
192.168.51.174:7006> rpush k v3 v2 v1 v0
(integer) 7
192.168.51.174:7006> lrange k 0 -1
1) "v6"
2) "v5"
3) "v4"
4) "v3"
5) "v2"
6) "v1"
7) "v0"
192.168.51.174:7006> lpush k v7 v8 v9
(integer) 10
192.168.51.174:7006> lrange k 0 -1
 1) "v9"
 2) "v8"
 3) "v7"
 4) "v6"
 5) "v5"
 6) "v4"
 7) "v3"
 8) "v2"
 9) "v1"
10) "v0"
192.168.51.174:7006> LREM k 1 v9    #移除集合k中一个值为v9的元素
(integer) 1
192.168.51.174:7006> lrange k 0 -1
1) "v8"
2) "v7"
3) "v6"
4) "v5"
5) "v4"
6) "v3"
7) "v2"
8) "v1"
9) "v0"
192.168.51.174:7006> lpush k v10 v10 v10 v10
(integer) 13
192.168.51.174:7006> lrange k 0 -1
 1) "v10"
 2) "v10"
 3) "v10"
 4) "v10"
 5) "v8"
 6) "v7"
 7) "v6"
 8) "v5"
 9) "v4"
10) "v3"
11) "v2"
12) "v1"
13) "v0"
192.168.51.174:7006> LREM k 3 v10  #移除集合k中三个值为v10的元素
(integer) 3
192.168.51.174:7006> lrange k 0 -1
 1) "v10"
 2) "v8"
 3) "v7"
 4) "v6"
 5) "v5"
 6) "v4"
 7) "v3"
 8) "v2"
 9) "v1"
10) "v0"
192.168.51.174:7006> LTRIM k 1 -1  #从下标1开始截取至结尾
OK
192.168.51.174:7006> lrange k 0 -1
1) "v8"
2) "v7"
3) "v6"
4) "v5"
5) "v4"
6) "v3"
7) "v2"
8) "v1"
9) "v0"
192.168.51.174:7006> RPOPLPUSH k k1  #移除最后一个元素并添加到k1集合中
"v0"
192.168.51.174:7006> lrange k1 0 -1
1) "v0"
192.168.51.174:7006> lrange k 0 -1
1) "v8"
2) "v7"
3) "v6"
4) "v5"
5) "v4"
6) "v3"
7) "v2"
8) "v1"
192.168.51.174:7006> lset k 3 value5  #对集合k中下标为3的元素重新赋值
OK
192.168.51.174:7006> lrange k 0 -1
1) "v8"
2) "v7"
3) "v6"
4) "value5"
5) "v4"
6) "v3"
7) "v2"
8) "v1"
192.168.51.174:7006> LINSERT k after v6 supper6  #集合k中元素v6后面添加supper6
(integer) 9
192.168.51.174:7006> lrange k 0 -1
1) "v8"
2) "v7"
3) "v6"
4) "supper6"
5) "value5"
6) "v4"
7) "v3"
8) "v2"
9) "v1"
192.168.51.174:7006> LINSERT k before v6 supper7  #集合k中元素v6前面添加supper7
(integer) 10
192.168.51.174:7006> lrange k 0 -1
 1) "v8"
 2) "v7"
 3) "supper7"
 4) "v6"
 5) "supper6"
 6) "value5"
 7) "v4"
 8) "v3"
 9) "v2"
10) "v1"
192.168.51.174:7006> 




3.Set(集合)元素唯一不重复

sadd(添加)、smembers(查看所有元素)、sismember(判断是否存在)、scard(查看长度)、srem(移除指定元素)、srandmember(抽随机)、spop(随机删除元素)、smove(移动指定元素到新的集合中)、sdiff(差集)、sinter(交集)、sunion(并集)

192.168.51.174:7006> MOVE k 1
(integer) 1
192.168.51.174:7006> sadd k v1 v2 v3 v4 v5 # 添加set集合元素
(integer) 5
192.168.51.174:7006> SMEMBERS k   #展示元素
1) "v1"
2) "v4"
3) "v3"
4) "v2"
5) "v5"
192.168.51.174:7006> SISMEMBER k v1   #是否存在元素v1  存在返回1
(integer) 1
192.168.51.174:7006> SISMEMBER k v7   #不存在返回0
(integer) 0
192.168.51.174:7006> SCARD k
(integer) 5
192.168.51.174:7006> smembers k
1) "v1"
2) "v4"
3) "v5"
4) "v2"
5) "v3"
192.168.51.174:7006> srem k v3   #删除元素
(integer) 1
192.168.51.174:7006> SMEMBERS k
1) "v1"
2) "v4"
3) "v5"
4) "v2"
192.168.51.174:7006> sadd k v6 v7 v8 v9
(integer) 4
192.168.51.174:7006> SMEMBERS k 
1) "v8"
2) "v1"
3) "v9"
4) "v7"
5) "v4"
6) "v5"
7) "v6"
8) "v2"
192.168.51.174:7006> SRANDMEMBER k     #随机抽取一个值
"v5"
192.168.51.174:7006> SRANDMEMBER k 1   #随机抽取一个值
1) "v2"
192.168.51.174:7006> SRANDMEMBER k 3   #随机抽取三个值
1) "v4"
2) "v5"
3) "v2"
192.168.51.174:7006> SMEMBERS k 
1) "v8"
2) "v1"
3) "v9"
4) "v7"
5) "v4"
6) "v5"
7) "v6"
8) "v2"
192.168.51.174:7006> spop k 1   # 随机删除一个元素
1) "v5"
192.168.51.174:7006> SMEMBERS k
1) "v8"
2) "v1"
3) "v9"
4) "v7"
5) "v4"
6) "v6"
7) "v2"
192.168.51.174:7006> smove k k1 v2  #移动指定元素到新set
(integer) 1
192.168.51.174:7006> SMEMBERS k1
1) "v2"
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> sadd k 0 1 2 3 4 5 6
(integer) 7
192.168.51.174:7006> sadd k1 3 4 5 6 7 8 9 
(integer) 7
192.168.51.174:7006> SMEMBERS k
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
192.168.51.174:7006> SMEMBERS k1
1) "3"
2) "4"
3) "5"
4) "6"
5) "7"
6) "8"
7) "9"
192.168.51.174:7006> SDIFF k k1  #获取 k 与 k1 的差集,可以是多个set
1) "0"
2) "1"
3) "2"
192.168.51.174:7006> SDIFF k1 k  #获取 k1 与 k 的差集,可以是多个set
1) "7"
2) "8"
3) "9"
192.168.51.174:7006> sinter k1 k #查询指定的set之间的交集,可以是多个set
1) "3"
2) "4"
3) "5"
4) "6"
192.168.51.174:7006> SUNION k k1   #查询指定的set之间的并集,可以是多个set
 1) "0"
 2) "1"
 3) "2"
 4) "3"
 5) "4"
 6) "5"
 7) "6"
 8) "7"
 9) "8"
10) "9"
192.168.51.174:7006> 







4.Hash(哈希)

 
hset(添加hash)、hget(查询)、hgetall(查询所有)、hdel(删除hash中指定的值)、hlen(获取hash的长度)、hexists(判断key是否存在)、②hkeys(获取所有key)、hvals(获取所有value)、hincrby(给值加增量)、hsetnx(存在不添加)

192.168.51.174:7006> flushall
OK
192.168.51.174:7006> hset k name KSJD age 18 gender 1   #创建hash对象k
(integer) 3
192.168.51.174:7006> hget k name    #获取k对象中元素值
"KSJD"
192.168.51.174:7006> hget k age
"18"
192.168.51.174:7006> HGETALL k    #获取k中所有的值,包含key
1) "name"
2) "KSJD"
3) "age"
4) "18"
5) "gender"
6) "1"
192.168.51.174:7006> hset k tec java   #添加元素
(integer) 1
192.168.51.174:7006> HGETALL k
1) "name"
2) "KSJD"
3) "age"
4) "18"
5) "gender"
6) "1"
7) "tec"
8) "java"
192.168.51.174:7006> HDEL k age tec  #删除元素 可以单个也可以多个,空格隔开
(integer) 2
192.168.51.174:7006> HGETALL k
1) "name"
2) "KSJD"
3) "gender"
4) "1"
192.168.51.174:7006> hlen k   # 获取长度
(integer) 2
192.168.51.174:7006> hexists k name   #判断是否存在该字段 ,存在返回1
(integer) 1
192.168.51.174:7006> hexists k age    #判断是否存在该字段,不存在返回0
(integer) 0
192.168.51.174:7006> 


5.zSet(有序集合)

zadd(添加)、zrange(查询)、zrangebyscore(排序小-大)、zrevrange(排序大-小)、zrangebyscore withscores(查询所有值包含key),zrem(移除元素)、zcard(查看元素个数)、zcount(查询指定区间内的元素个数)

192.168.51.174:7006> clear
192.168.51.174:7006> flushall
OK
192.168.51.174:7006> zadd k 1 one 2 two 3 three 4 four 5 five  # 创建zset
(integer) 5
192.168.51.174:7006> zrange k 0 -1  # #查询所有的值
1) "one"
2) "two"
3) "three"
4) "four"
5) "five"
192.168.51.174:7006> ZRANGEBYSCORE k -inf +inf  #将zset的值根据key来从小到大排序并输出,
#-inf 负无穷  +inf 正无穷
1) "one"
2) "two"
3) "three"
4) "four"
5) "five"
192.168.51.174:7006> ZRANGEBYSCORE k 0 1  #只查询key<=1的值并且排序从小到大
1) "one"
192.168.51.174:7006> ZRANGEBYSCORE k 2 4  #查询2<=key<=4的值并且排序从小到大
1) "two"
2) "three"
3) "four"
192.168.51.174:7006> ZREVRANGE k 1 -1
1) "four"
2) "three"
3) "two"
4) "one"
192.168.51.174:7006> ZREVRANGE k 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
192.168.51.174:7006> ZRANGEBYSCORE k  -inf +inf withscores
 1) "one"
 2) "1"
 3) "two"
 4) "2"
 5) "three"
 6) "3"
 7) "four"
 8) "4"
 9) "five"
10) "5"
192.168.51.174:7006> zrange k 0 -1
1) "two"
2) "three"
3) "four"
4) "five"
192.168.51.174:7006> zcard k     #获取长度
(integer) 4
192.168.51.174:7006> zcount k 1 10  #获取
(integer) 4
192.168.51.174:7006> zcount k 2 4   #指定区间内的元素个数
(integer) 3
192.168.51.174:7006> zcount k 2 5
(integer) 4
192.168.51.174:7006> 

三: 三大特殊数据类型的学习和理解

1.Geospatial: 地理位置


城市经纬度查询: 经纬度查询
注意点1:两极无法直接添加
注意点2:有效的经度从-180度到180度。
注意点3:有效的纬度从-85.05112878度到85.05112878度。
注意点4:m 为米。km 为千米。mi 为英里。ft 为英尺。
geoadd(添加)、geopos(查看)、geodist(计算距离)、georadius(查询附近位置)、georadiusbymember (查找指定元素指定范围内的元素)、geohash (返回经纬度的hash值)、zrange、zrem(使用zset命令操作geo)

192.168.51.174:7006> flushall
OK
192.168.51.174:7006> clear
192.168.51.174:7006> geoadd city 118.8921 31.32751 nanjing 117.30794 31.79322 hefei 102.82147 24.88554 kunming 91.13775 29.65262 lasa 116.23128 40.22077 beijing 106.54041 29.40268 chongqing     # 插入城市坐标
(integer) 6
192.168.51.174:7006> zrange city 0 -1  #查看所有城市,和zset命令一致
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
192.168.51.174:7006> GEOPOS city nanjing  #查看城市具体坐标
1) 1) "118.89209836721420288"
   2) "31.32750976275760735"
192.168.51.174:7006> GEOPOS city beijing nanjing   #查看多个城市具体坐标
1) 1) "116.23128265142440796"
   2) "40.22076905438526495"
2) 1) "118.89209836721420288"
   2) "31.32750976275760735"
192.168.51.174:7006> GEODIST city beijing nanjing   #计算城市之间的距离  m
"1017743.1413"
192.168.51.174:7006> GEODIST city beijing nanjing km  #km单位
"1017.7431"
192.168.51.174:7006> zrange city 0 -1
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
192.168.51.174:7006> GEORADIUS city 117.10613  36.70494 500 km #获取该经纬度500km以内的坐标
1) "beijing"
192.168.51.174:7006> GEORADIUS city 117.10613  36.70494 1000 km 
1) "beijing"
2) "hefei"
3) "nanjing"
192.168.51.174:7006> GEORADIUS city 117.10613  36.70494 1000 km withcoord  #详情
1) 1) "beijing"
   2) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) 1) "118.89209836721420288"
      2) "31.32750976275760735"
192.168.51.174:7006> GEORADIUS city 117.10613  36.70494 1000 km withcoord withdist
1) 1) "beijing"
   2) "398.3994"
   3) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "546.6271"
   3) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) "620.3231"
   3) 1) "118.89209836721420288"
      2) "31.32750976275760735"
192.168.51.174:7006> GEORADIUS city 117.10613  36.70494 1000 km withcoord withdist withhash
1) 1) "beijing"
   2) "398.3994"
   3) (integer) 4069896088584598
   4) 1) "116.23128265142440796"
      2) "40.22076905438526495"
2) 1) "hefei"
   2) "546.6271"
   3) (integer) 4052763834193093
   4) 1) "117.30793744325637817"
      2) "31.79321915080526395"
3) 1) "nanjing"
   2) "620.3231"
   3) (integer) 4054278565840695
   4) 1) "118.89209836721420288"
      2) "31.32750976275760735"
192.168.51.174:7006> GEORADIUSBYMEMBER city beijing 1000 km   #距离北京1000km以内的城市
1) "beijing"
2) "hefei"
192.168.51.174:7006> zrange city 0 -1
1) "lasa"
2) "kunming"
3) "chongqing"
4) "hefei"
5) "nanjing"
6) "beijing"
192.168.51.174:7006> zrem city lasa    #根据名称删除元素
(integer) 1
192.168.51.174:7006> zrange city 0 -1
1) "kunming"
2) "chongqing"
3) "hefei"
4) "nanjing"
5) "beijing"
192.168.51.174:7006> 



2.Hyperloglog: 基数

但是再Redis中,可能会有一定的误差性。 官方给出的误差率是0.81%。
Hyperloglog的优点: 占用的内存是固定的,2^64个元素,相当于只需要12kb的内存即可。效率极高!

pfadd(添加数据集)、pfcount(统计数据集)、pfmegre(合并数据集-自动去重)


192.168.51.174:7006> pfadd k 1 2 3 4 5 6 7  #添加数据
(integer) 1
192.168.51.174:7006> PFCOUNT k   #统计数据
(integer) 7
192.168.51.174:7006> pfadd k1 5 6 7 8 9 0 
(integer) 1
192.168.51.174:7006> PFCOUNT k1
(integer) 6
192.168.51.174:7006> PFMERGE k2 k k1   #合并数据成为一个新数据,自动去重
OK
192.168.51.174:7006> PFCOUNT k2
(integer) 10
192.168.51.174:7006> 

 3.Bitmap: 位存储

Bitmap 位图,数据结构! 都是操作二进制位来进行记录,就只有0 和 1 两个状态!
①setbit(添加)、getset(获取)、bitcount(统计)操作

192.168.51.174:7006> flushall
OK
192.168.51.174:7006> setbit k 1 1  #添加 1 为 1
(integer) 0
192.168.51.174:7006> GETBIT k 1    #获取 1
(integer) 1
192.168.51.174:7006> setbit k 2 0
(integer) 0
192.168.51.174:7006> GETBIT k 2
(integer) 0
192.168.51.174:7006> SETBIT k 3 1
(integer) 0
192.168.51.174:7006> SETBIT k 4 1
(integer) 0
192.168.51.174:7006> SETBIT k 5 1
(integer) 0
192.168.51.174:7006> BITCOUNT k   #统计k
(integer) 4
192.168.51.174:7006> 

JAVA

SpringBoot整合Redis

        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.1.7.RELEASE</version>
        </dependency>
        <!--序列化-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
            <scope>compile</scope>
        </dependency>
        <!--lombok,自动生成set、get等方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>compile</scope>
        </dependency>
server:
  port: 8080

spring:
  # redis
  redis:
    host: 192.168.51.174 #IP
    port: 7006 # 端口
    password: ********
    database: 1
    #lettuce:
    timeout: 7200s # 连接超时时间
    lettuce:
      pool:
        # 连接池中的最小空闲连接
        min-idle: 0
        # 连接池中的最大空闲连接
        max-idle: 8
        # 连接池的最大数据库连接数
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms

 redisTemplate  #操作不同的数据类型,api和我们的指令是一样的 
 opsForValue  #操作字符串 类似String 
 opsForList  #操作List 类似List 
 opsForSet  #操作set
 opsForHash  #操作hash
 opsForZSet  #操作zset
 opsForGeo   #操作geo
 opsForHyperLogLog  #操作HyperLogLog
 除了进本的操作,我们常用的方法都可以直接通过redisTemplate操作,比如事务,和基本的 CRUD 
 获取redis的连接对象 
 RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); 
 connection.flushDb(); 
 connection.flushAll();

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
public final class RedisUtils {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private static final Long LOCK_EXPIRE = 1000L * 60; // 默认锁时间 1分钟


    /**
     * 分布式锁,默认锁定1分钟
     *
     * @param key key值
     * @return 是否获取到
     */
    public boolean lock(String key) {
        return lock(key, LOCK_EXPIRE);
    }


    /**
     * redis分布式锁
     *
     * @param key        锁定的key
     * @param lockExpire 过期时间
     * @param timeUnit   时间单位
     * @return
     */
    public boolean lock(String key, Long lockExpire, TimeUnit timeUnit) {
        return lock(key, timeUnit.toMillis(lockExpire));
    }


    /**
     * redis分布式锁 成功加锁返回true,锁已存在或加锁失败返回false
     *
     * @param key        锁定的key
     * @param lockExpire 过期时间,单位为毫秒
     * @return
     */
    public boolean lock(String key, Long lockExpire) {
        
        return setNx(key, lockExpire, lockExpire);
    }


    /**
     * 模糊查询出所有合适的 keys (键务必为String格式)
     *
     * @param prefix 键
     * @return
     */
    public Set<String> likeKeys(String prefix) {
        try {
            return redisTemplate.keys(prefix + "*");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(毫秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.MILLISECONDS);
            }
            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.MILLISECONDS);
    }

    /**
     * 判断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));
            }
        }
    }

    /**
     * 普通缓存获取
     *
     * @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 setKey(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.MILLISECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入, 不存在放入,存在返回
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean setNx(String key, Object value) {
        try {
            redisTemplate.opsForValue().setIfAbsent(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 setNx(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.MILLISECONDS);
            } 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);
    }


    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> getHash(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object getHash(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean setHash(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 setHash(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;
        }
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean setHash(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 setHash(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  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void delHash(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hasHashKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hashIncr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hashDecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> getSetKey(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 hasSetKey(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 setSetKey(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 setSetKey(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 getSetKeySize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long removeSet(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 键
     * @return
     */
    public long getListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> getList(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object getList(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 setListRight(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean setListRight(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 setListRight(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 值
     * @param time  时间(秒)
     * @return
     */
    public boolean setListRight(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 updateListIndex(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 removeList(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }


}
 

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Java实现分布式锁通常有以下几种方式: 1. 使用数据库实现分布式锁: 在数据库中创建一张表,表中包含一个字段表示锁的状态,当需要获取锁时,使用数据库的乐观锁机制,尝试更新该字段为已占用的状态,如果更新成功,则获取到了锁,否则表示锁已被其他进程占用。 2. 使用 Redis 实现分布式锁: Redis 是一个高性能的内存数据库,支持原子性操作,因此也可以用来实现分布式锁。在 Redis 中,可以使用 SET 命令将一个键设置为一个值,并设置过期时间,这样就可以在获取锁时使用 SETNX 命令(即 SET if Not eXists)来尝试设置锁的值,如果设置成功,则获取到了锁,否则表示锁已被其他进程占用。 3. 使用 Java 的并发库实现分布式锁: Java 提供了多种并发库,其中有一些可以用来实现分布式锁。例如可以使用 Java 并发库中的 ReentrantLock 类来实现分布式锁。 ReentrantLock 类提供了 tryLock() 方法,可以在获取锁时使用该方法尝试获取锁 ### 回答2: Java可以通过多种方式实现分布式锁,下面是其中一种基于ZooKeeper实现分布式锁简单示例。 首先,我们需要引入ZooKeeper的依赖库,并创建一个ZooKeeper实例。然后,我们可以使用ZooKeeper的API来创建一个节点作为分布式锁的锁路径。 ```java import org.apache.zookeeper.*; public class DistributedLock { private ZooKeeper zooKeeper; private String lockPath; public DistributedLock(String zookeeperAddress, String lockPath) { try { this.zooKeeper = new ZooKeeper(zookeeperAddress, 5000, null); this.lockPath = lockPath; } catch (Exception e) { e.printStackTrace(); } } public void lock() { try { // 创建临时有序节点作为锁 String lockNode = zooKeeper.create(lockPath + "/lock-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); while (true) { // 获取锁路径下的所有子节点 List<String> children = zooKeeper.getChildren(lockPath, false); // 找到序号最小的节点 String[] nodes = children.toArray(new String[0]); Arrays.sort(nodes); // 如果当前节点是序号最小的节点,则表示获取到锁 if (lockNode.equals(lockPath + "/" + nodes[0])) { return; } // 监听序号比自己小1的节点,等待释放锁 String prevNode = nodes[Arrays.binarySearch(nodes, lockNode.substring(lockNode.lastIndexOf("/") + 1)) - 1]; ZooKeeperWatcher watcher = new ZooKeeperWatcher(); zooKeeper.exists(lockPath + "/" + prevNode, watcher); synchronized (watcher) { watcher.wait(); } } } catch (Exception e) { e.printStackTrace(); } } public void unlock() { try { zooKeeper.close(); } catch (Exception e) { e.printStackTrace(); } } } class ZooKeeperWatcher implements Watcher { @Override public void process(WatchedEvent event) { synchronized (this) { this.notifyAll(); } } } ``` 上述代码实现了一个简单分布式锁,它的原理是通过ZooKeeper的临时有序节点来实现。通过创建临时有序节点,每个节点都会有一个唯一的序号,序号最小的节点表示持有锁,其他节点需要监听比自己序号小1的节点,并等待其释放锁。 这个实现是一个简单的例子,可以根据实际需求进行扩展和改进。例如,可以添加超时机制以避免死锁,或者使用Redis实现分布式锁。 ### 回答3: Java实现分布式锁可以使用以下几种方式: 1. 基于数据库实现:可以使用数据库的事务机制和唯一索引来实现分布式锁。对于需要加锁的资源,在数据库表中创建一条记录,将其作为锁的标识,其他线程或进程在获取锁时会尝试插入同一条记录,如果插入成功则表示获取到锁,否则表示锁被其他线程或进程占用。 2. 基于缓存实现:可以使用分布式缓存工具如Redis或ZooKeeper来实现分布式锁。在缓存中创建一个带有超时时间的key,其他线程或进程在获取锁时会尝试设置同一个key,如果设置成功则表示获取到锁,否则表示锁被其他线程或进程占用。同时,需要保证设置key和业务操作的原子性,可以使用缓存工具提供的原子操作来实现。 3. 基于ZooKeeper实现:ZooKeeper是一个开源的分布式协调服务,可以用于实现分布式锁。在ZooKeeper中创建一个有序临时节点,每个线程或进程按照创建顺序尝试获取锁,如果当前节点是最小的节点,则表示获取到锁,否则监听前一个节点的删除事件,当前一个节点被删除时再次尝试获取锁。 以上是常见的几种Java实现分布式锁的方式,可以根据具体的业务需求选择合适的方式来实现。同时,在使用分布式锁时需要考虑性能、可用性和一致性等方面的问题,对于高并发和高可用性的场景,可能需要结合其他的分布式协调工具或技术来实现更复杂的分布式锁机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值