一、5大基礎類型
1. 基本命令
keys * #查看當前庫所有k
set k v #設置k, v
get k #獲取k
expire k 10 #設置key過期時間 單位秒
ttl k #查看k的剩餘時間
select 0 #切換數據庫 0/16 默認16個庫 配置文件中配置
flushdb #清空當前庫k
flushall #清空所有庫k
move k #移除k
exists k,k1 #查詢k是否存在
type k #查詢k對應的v存儲類型
2. String類型
append k v #追加字符串,如果k不存在就相當添加
strlen k #獲取字符串長度
-----------------------------
incr k #原子加1
decr k #原子減1
incrby k 10 #原子加10 10是步長 可用在瀏覽量
decrby k 10 #原子減10 10是步長
-----------------------------
getrange k 0 3 #截取字符串 從0位置-3位置 4個字符串
getrange k 0 -1 #去字符串所有內容
-----------------------------
setrange k 1 xxx #從下標位1開始替換後面的內容
-----------------------------
setex k v 60 #設置k,v,過期時間
-----------------------------
setnx k v #k不存在再設置值(常在分佈式鎖中使用)
-----------------------------
mset k1 v1 k2 v2 k3 v3 #批量設置k,v
msetnx k1 v1 k4 v4 #存在的key,值就不設置了
mget k1 k2 k3 #獲取多個key值
-----------------------------
getset k v #先獲取在設置, CAS 原子操作
e.g
114.116.230.154:6397> getset db redis
(nil)
114.116.230.154:6397> get db
"redis"
114.116.230.154:6397> getset db mongodb
"redis"
114.116.230.154:6397> get db
"mongodb"
3. List
list 可以用來實現隊列、棧,所有的命令都是以==L==開頭。
#從左向右添加數據,如果集合不存在創建集合
114.116.230.154:6397> lpush list one #lpush:從左向右添加,後添加的總是在頭部0的位置(棧)
(integer) 1
114.116.230.154:6397> lpush list two
(integer) 2
114.116.230.154:6397> lpush list three
(integer) 3
114.116.230.154:6397> lrange list 0 -1 #獲取list中的所有值
1) "three"
2) "two"
3) "one"
114.116.230.154:6397> lrange list 0 1 #獲取list中的區間值,如果獲取第一個值 lrange list 0 0
1) "three"
2) "two"
------------------------------------------
#從右向左添加數據,如集合不存在添加集合
114.116.230.154:6397> rpush list right #rpush:從右向左添加
(integer) 4
114.116.230.154:6397> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
------------------------------------------
#從左邊或者右邊彈出元素
114.116.230.154:6397> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
114.116.230.154:6397> lpop list #彈出左邊第一個元素,並移除
"three"
114.116.230.154:6397> lrange list 0 -1
1) "two"
2) "one"
3) "right"
114.116.230.154:6397> rpop list #彈出右邊第一個元素,並移除
"right"
114.116.230.154:6397> lrange list 0 -1
1) "two"
2) "one"
# lpush + lpop(棧),lpush + rpop(隊列)
-----------------------------------------
#獲取集合中指定下標元素
114.116.230.154:6397> lrange list 0 -1 #展示list集合中所有元素
1) "two"
2) "one"
114.116.230.154:6397> lindex list 0 #根據list集合下標獲取集合元素
"two"
114.116.230.154:6397> lindex list 1
"one"
-----------------------------------------
#獲取集合長度
114.116.230.154:6397> lrange list 0 -1
1) "two"
2) "one"
114.116.230.154:6397> llen list #獲取list集合長度
(integer) 2
-----------------------------------------
#移除集合中的指定元素值,並指定移除幾個
114.116.230.154:6397> lpush list one two three three #從左向右添加值
(integer) 4
114.116.230.154:6397> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
114.116.230.154:6397> lrem list 1 one #移除指定值one,並移除1個
(integer) 1
114.116.230.154:6397> lrange list 0 -1
1) "three"
2) "three"
3) "two"
(0.53s)
114.116.230.154:6397> lrem list 3 three #移除指定值three,並移除3個,但實際就2個所以都移除了。
(integer) 2
114.116.230.154:6397> lrange list 0 -1
1) "two"
---------------------------------------
#結合修剪,截取指定下標 n~m 的元素包含n,m的內容
114.116.230.154:6397> lrange mylist 0 -1
1) "h5"
2) "h4"
3) "h3"
4) "h2"
5) "h1"
114.116.230.154:6397> ltrim mylist 1 3 #ltrim:集合修剪操作,只保留下標1~3的元素
OK
114.116.230.154:6397> lrange mylist 0 -1
1) "h4"
2) "h3"
3) "h2"
---------------------------------------
#將一個集合的最後一個元素pop,push到另一個集合中
114.116.230.154:6397> lrange mylist 0 -1
1) "h6"
2) "h5"
3) "h4"
4) "h3"
5) "h2"
114.116.230.154:6397> rpoplpush mylist newlist #從mylist最後一個元素移除,到新列表newlist
"h2"
114.116.230.154:6397> lrange newlist 0 -1
1) "h2"
114.116.230.154:6397> lrange mylist 0 -1
1) "h6"
2) "h5"
3) "h4"
4) "h3"
---------------------------------------
#指定下標賦值
114.116.230.154:6397> lrange mylist 0 -1
1) "h6"
2) "h5"
3) "h4"
4) "h3"
114.116.230.154:6397> lset list 0 hdx #指定下標賦值list不存在報錯,所以先lpush或rpush
(error) ERR no such key
114.116.230.154:6397> lset mylist 1 h7 #向mylist集合的下標 1 處賦值 h7, 如下標不存在也會報錯
OK
114.116.230.154:6397> lrange mylist 0 -1 #結果原下標 1 處的 h5 被覆蓋
1) "h6"
2) "h7"
3) "h4"
4) "h3"
---------------------------------------
#指定內容元素前or後插入新元素
114.116.230.154:6397> lrange mylist 0 -1
1) "h6"
2) "h7"
3) "h4"
4) "h3"
114.116.230.154:6397> linsert mylist before h7 hdx #向mylist集合中h7元素前面插入hdx元素
(integer) 5
114.116.230.154:6397> lrange mylist 0 -1
1) "h6"
2) "hdx"
3) "h7"
4) "h4"
5) "h3"
# 操作類似一個連表 [before] Node [after]
小結
底層實現相當一個連表,比如lpush是向頭節點插入數據,rpush是向尾節點插入數據。可以向某個具體節點插入數據 比如 linsert。
可用用作隊列,棧
4. set
set值是不能重複的,set的命令都是==S==開頭
#set的基本操作
114.116.230.154:6397> sadd myset hello #向myset集合中set值
(integer) 1
114.116.230.154:6397> sadd myset hdx
(integer) 1
114.116.230.154:6397> smembers myset #展示myset集合中所有值
1) "hdx"
2) "hello"
114.116.230.154:6397> sismember myset hdx #查詢某個值(hdx),是否存在集合中,存在返回1
(integer) 1
---------------------------------------
#獲取set集合元素個數
114.116.230.154:6397> smembers myset
1) "hdx"
2) "hello"
114.116.230.154:6397> scard myset #查看set集合元素個數
(integer) 2
---------------------------------------
#移除set集合元素
114.116.230.154:6397> smembers myset #展示set集合中的元素[hdx, hello]
1) "hdx"
2) "hello"
114.116.230.154:6397> srem myset hdx #移除set集合中的hdx元素
(integer) 1
114.116.230.154:6397> scard myset #查詢set集合中元素個數
(integer) 1
114.116.230.154:6397> smembers myset #展示set集合中全部元素,只剩下hello
1) "hello"
----------------------------------------
#從set集合中隨機獲取指定個數元素
114.116.230.154:6397> sadd myset a b c d e f g #向set集合中添加7個元素
(integer) 7
114.116.230.154:6397> smembers myset #展示set集合中所用元素
1) "d"
2) "c"
3) "a"
4) "g"
5) "f"
6) "e"
7) "b"
114.116.230.154:6397> srandmember myset 1 #隨機獲取 1 個元素
1) "b"
114.116.230.154:6397> srandmember myset 2 #隨機獲取 2 個元素
1) "a"
2) "g"
#實現抽獎需求
----------------------------------------
#將一個元素從一個集合移動到另一個集合
114.116.230.154:6397> smembers myset
1) "a"
2) "g"
3) "f"
4) "c"
5) "d"
6) "e"
7) "b"
114.116.230.154:6397> smove myset newset a #將myset集合中的a元素移動到newset集合中
(integer) 1
114.116.230.154:6397> smembers newset
1) "a"
114.116.230.154:6397> smembers myset
1) "g"
2) "f"
3) "c"
4) "d"
5) "e"
6) "b"
---------------------------------------
#差集
#交集
#並集
#差集
114.116.230.154:6397> smembers myset #myset集合元素
1) "g"
2) "f"
3) "c"
4) "d"
5) "e"
6) "b"
114.116.230.154:6397> smembers newset #newset集合元素
1) "a"
2) "x"
3) "y"
4) "b"
5) "z"
114.116.230.154:6397> sdiff myset newset #myset與newset的差集(myset中哪些元素是newset沒有的,比如 b元素 )
1) "f"
2) "g"
3) "d"
4) "c"
5) "e"
114.116.230.154:6397> sdiff newset myset #newset與myset的差集(newset中哪些元素是myset中沒有的,比如 b元素)
1) "y"
2) "x"
3) "a"
4) "z"
#根據 myset,newset的順序不同,結果集也不同。
-----------------------------
#交集
114.116.230.154:6397> smembers myset
1) "g"
2) "f"
3) "c"
4) "d"
5) "e"
6) "b"
114.116.230.154:6397> smembers newset
1) "a"
2) "x"
3) "y"
4) "b"
5) "z"
114.116.230.154:6397> sinter myset newset #myset與newset的交集 b
1) "b"
114.116.230.154:6397> sinter newset myset #newset與myset的交集 b
1) "b"
#找出兩個集合共有的元素
-----------------------------
#並集
114.116.230.154:6397> smembers myset
1) "g"
2) "f"
3) "c"
4) "d"
5) "e"
6) "b"
114.116.230.154:6397> smembers newset
1) "a"
2) "x"
3) "y"
4) "b"
5) "z"
114.116.230.154:6397> SUNION myset newset #myset 與newset的並集
1) "c"
2) "d"
3) "e"
4) "b"
5) "a"
6) "f"
7) "g"
8) "y"
9) "x"
10) "z"
#相當兩個集合元素去重
5. hash
String數據類型是key:value
hash數據類型是 key : (k:v),也可以理解成一對對象裏面有多個屬性。hash命令是以==h==開頭。
#hash 的形式
114.116.230.154:6397> hset myhash filed1 hdx #向myhash中設置一個鍵值對 k是field1,v是hdx
(integer) 1
114.116.230.154:6397> hget myhash filed1 #獲取myhash中field1屬性的值
"hdx"
114.116.230.154:6397> hmset myhash field1 hello field2 world #hmset向myhash中設置多個鍵值
OK
114.116.230.154:6397> hmget myhash field1 field2 #hmget 通過多個鍵從myhash中取出多個值
1) "hello"
2) "world"
114.116.230.154:6397> hgetall myhash #取出myhash的所有鍵和值
1) "filed1" #鍵
2) "hdx" #值
3) "field1" #鍵
4) "hello" #值
5) "field2" #鍵
6) "world" #值
114.116.230.154:6397> hkeys myhash #獲取myhahs中所有的key
1) "filed1"
2) "field2"
114.116.230.154:6397> hvals myhash #獲取myhash中所有的value
1) "hdx"
2) "world"
-----------------------------------
114.116.230.154:6397> hgetall myhash
1) "filed1" #鍵
2) "hdx" #值
3) "field2" #鍵
4) "world" #值
114.116.230.154:6397> hlen myhash #獲取myhash中的長度,結果證明是鍵值對的個數。
(integer) 2
-----------------------------------
114.116.230.154:6397> hgetall myhash
1) "filed1"
2) "hdx"
3) "field2"
4) "world"
114.116.230.154:6397> hexists myhash field2 #判斷 myhash中field2屬性是否存在
(integer) 1
-----------------------------------
114.116.230.154:6397> hset myhash field3 5
(integer) 1
114.116.230.154:6397> hincrby myhahs field3 1 #field3屬性自增 1
(integer) 1
114.116.230.154:6397> hincrby myhash field3 -1 #field3屬性自減 1
(integer) 4
hash數據類型可以用於對象的存儲,而string只適合簡單的字符串存儲。
6. zset
zset 命令與set類似,zset命令以==z==開頭,zset是有序的集合,只支持最小值到最大值排序。
114.116.230.154:6397> zadd salary 500 hdx
(integer) 1
114.116.230.154:6397> zadd salary 1500 haha
(integer) 1
114.116.230.154:6397> zadd salary 2500 sanmao
(integer) 1
114.116.230.154:6397> zrangebyscore salary -inf +inf
1) "hdx"
2) "haha"
3) "sanmao"
114.116.230.154:6397> zrangebyscore salary +inf -inf #不支持
(empty list or set)
----------------------------------------
114.116.230.154:6397> zrange salary 0 -1 #查詢所有key
1) "hdx"
2) "haha"
3) "sanmao"
114.116.230.154:6397> zrem salary sanmao #移除sanmao元素
(integer) 1
114.116.230.154:6397> zrange salary 0 -1
1) "hdx"
2) "haha"
----------------------------------------
114.116.230.154:6397> zcard salary #查看個數
(integer) 2
二、3大特殊類型
1. geospatial 地理空間
朋友定位,附近的人,打車
#添加城市經緯度 前面是精度[-180~180] 緯度[-85~85]
114.116.230.154:6397> geoadd china:city 116.40 39.91 beijing
(integer) 1
114.116.230.154:6397> geoadd china:city 121.47 31.23 shanghai
(integer) 1
114.116.230.154:6397> geoadd china:city 106.50 29.53 chongqing
(integer) 1
114.116.230.154:6397> geoadd china:city 114.05 22.52 shenzhen
(integer) 1
114.116.230.154:6397> geoadd china:city 120.16 30.24 hangzhou
(integer) 1
114.116.230.154:6397> geoadd china:city 108.96 34.26 xian
(integer) 1
---------------------------------
#geopos 獲取城市北京經緯度
114.116.230.154:6397> geopos china:city beijing
1) "116.39999896287918"
2) "39.909999566644508"
---------------------------------
#geopos兩個城市之間的直線距離
114.116.230.154:6397> geopos china:city beijing
1) 1) "116.39999896287918"
2) "39.909999566644508"
114.116.230.154:6397> geodist china:city beijing shanghai
"1068370.2525"
(1.72s)
114.116.230.154:6397> geodist china:city beijing shanghai km
"1068.3703"
---------------------------------
#georadius附近的人,給出一個精度查詢半徑之內的值
114.116.230.154:6397> georadius china:city 110 30 500 km
1) "chongqing"
2) "xian"
#精度110緯度30 半徑500千米以內的城市
-----------------
#精度110緯度30 半徑500千米以內的城市,並顯示直線距離withdist,經緯度withcoord,查詢個數count
114.116.230.154:6397> georadius china:city 110 30 500 km withcoord withdist count 1
1) 1) "chongqing"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
------------------
#查詢某個城市(key)的半徑400千米的城市
114.116.230.154:6397> georadiusbymember china:city hangzhou 400 km
1) "hangzhou"
2) "shanghai"
------------------
#geospatial底層是通過zset實現的,所以移除元素可以是用zrem
114.116.230.154:6397> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
114.116.230.154:6397> zrem china:city xian
(integer) 1
114.116.230.154:6397> zrange china:city 0 -1
1) "chongqing"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "beijing"
2. hyperloglog
是什麼?是兩個set集合去重合並返回元素數量。官方0.81%錯誤率,如果允許誤差建議使用,效率高節省空間。如果不允許誤差那麼不建議使用。
114.116.230.154:6397> pfadd mykey a b c d e f g h i j #添加不可重複的元素集合
(integer) 1
114.116.230.154:6397> pfcount mykey #獲取元素數量
(integer) 10
114.116.230.154:6397> pfadd mykey2 i j z x c v b n m
(integer) 1
114.116.230.154:6397> pfcount mykey
(integer) 10
114.116.230.154:6397> pfmerge mykey3 mykey mykey2 #合併mykye和mykey2元素,結果存到mykey3中
OK
114.116.230.154:6397> pfcount mykey3 #mykey3數量15,將兩個集合去重合並統計數值
(integer) 15
3. bitmaps
位存儲,記錄0,1狀態
114.116.230.154:6397> setbit sign 0 1 #
(integer) 0
114.116.230.154:6397> setbit sign 1 0
(integer) 0
114.116.230.154:6397> setbit sign 2 0
(integer) 0
114.116.230.154:6397> setbit sign 3 1
(integer) 0
114.116.230.154:6397> setbit sign 4 1
(integer) 0
114.116.230.154:6397> setbit sign 5 0
(integer) 0
114.116.230.154:6397> setbit sign 6 0
(integer) 0
114.116.230.154:6397> getbit sign 3 #獲取到sign裏面3 的狀態
(integer) 1
114.116.230.154:6397> getbit sign 6 #獲取到sign裏面6 的狀態
(integer) 0
114.116.230.154:6397> bitcount sign #獲取到sign裏面狀態爲1的個數
(integer) 3
三、事務
1.redis事務特性
redis的事務是不保證原子性的(redis單條命令是保證原子性的)
redis 事務沒有隔離級別概念
redis事務的特性:一次性、順序性、排他性
redis事務:
開啓事務(multi) -> 命令入隊(...) -> 執行事務(exec)
2.redis事務基本操作
#正常開啓事務執行事務
114.116.230.154:6397> multi #開啓事務
OK
114.116.230.154:6397> set k1 v1
QUEUED
114.116.230.154:6397> set k2 v2
QUEUED
114.116.230.154:6397> get k2
QUEUED
114.116.230.154:6397> set k3 v3
QUEUED
114.116.230.154:6397> exec #執行隊列,並結束事務
1) OK
2) OK
3) "v2"
4) OK
-----------------------
114.116.230.154:6397> multi
OK
114.116.230.154:6397> set k1 v1
QUEUED
114.116.230.154:6397> set k2 v2
QUEUED
114.116.230.154:6397> set k4 v4
QUEUED
114.116.230.154:6397> discard #取消事務,入隊的命令都不會執行
OK
114.116.230.154:6397> get k4
(nil)
3.事務錯誤異常情況
類比編譯時異常:就是語法或命令錯誤導致的無法編譯或執行,這類的異常在redis事務中是不會被執行的。
114.116.230.154:6397> multi
OK
114.116.230.154:6397> set k1 v1
QUEUED
114.116.230.154:6397> set k2 v2
QUEUED
114.116.230.154:6397> set k3 v3
QUEUED
114.116.230.154:6397> getset k3
(error) ERR wrong number of arguments for 'getset' command
114.116.230.154:6397> set k4 v4
QUEUED
114.116.230.154:6397> set k5 v5
QUEUED
114.116.230.154:6397> exec
(error) EXECABORT Transaction discarded because of previous errors.
運行時異常:編譯器在編譯的時候無法發現錯誤,只有在程序運行過程中產生的錯誤。這類錯誤redis事務中是會被執行的。
114.116.230.154:6397> multi
OK
114.116.230.154:6397> set k1 v1
QUEUED
114.116.230.154:6397> incr k1
QUEUED
114.116.230.154:6397> set k2 v2
QUEUED
114.116.230.154:6397> get k2
QUEUED
114.116.230.154:6397> exec
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "v2"
114.116.230.154:6397> get k1
"v1"
114.116.230.154:6397> get k2
"v2"
4.事務監控
監控:watch -- 樂觀鎖
#正常執成功,事務正常結束,事務期間沒有發生任何錯誤
114.116.230.154:6397> set money 100
OK
114.116.230.154:6397> set out 0
OK
114.116.230.154:6397> watch money #監視money值(樂觀鎖)
OK
114.116.230.154:6397> multi
OK
114.116.230.154:6397> decrby money 20
QUEUED
114.116.230.154:6397> incrby out 20
QUEUED
114.116.230.154:6397> exec
1) (integer) 80
2) (integer) 20
多線程演示 watch
#第一個線程操作
114.116.230.154:6397> watch money #監視money
OK
114.116.230.154:6397> multi #開啓事務
OK
114.116.230.154:6397> decrby money 20
QUEUED
114.116.230.154:6397> incrby out 20
QUEUED
#第二個線程操作
114.116.230.154:6397> decrby money 10 #減掉10塊
(integer) 70
#第一個線程操作
114.116.230.154:6397> exec #第一個線程執行事務不成功
(nil)
#第一線程操作失敗之後可以繼續操作
114.116.230.154:6397> unwatch #接觸監控
OK
114.116.230.154:6397> watch money #重新獲取監控
OK
114.116.230.154:6397> multi #開啓事務繼續執行後續命令
OK
114.116.230.154:6397> decrby mone 20
QUEUED
114.116.230.154:6397> incrby out 20
QUEUED
114.116.230.154:6397> exec
1) (integer) -20
2) (integer) 40
監控總結:money值通過 watch監視,如果在一個線程事務中正在執行還未提交,那麼被監視的對象被另外一個線程修改了,再提交事務的時候會失敗。這種機制符合樂觀鎖機制,認爲什麼時候值都不會被改變,之後在提交事務的時候去判斷值是否與之前一致,一致成功反之失敗。經典cas原理。
如果是悲觀鎖:那麼就是money這個值認爲什麼時候都有可能被修改,加鎖之後只有當前加鎖線程可以操作money。其他線程只有等待money鎖釋放後才能操作。
所以在上面的例子中redis的監控(watch)機制顯然是樂觀鎖機制。
四、jedis
p23