視頻課程鏈接:http://edu.51cto.com/course/14463.html
四、Key操作命令
1. 命令列表
命令用法 | 解釋 |
---|---|
keys pattern | 獲取所有匹配pattern參數的Keys。需要說明的是,在我們的正常操作中應該儘量避免對該命令的調用,因爲對於大型數據庫而言,該命令是非常耗時的,對Redis服務器的性能打擊也是比較大的。pattern支持glob-style的通配符格式,如*表示任意一個或多個字符,?表示任意字符,[abc]表示方括號中任意一個字母。 |
del key [key...] | 從數據庫刪除中參數中指定的keys,如果指定鍵不存在,則直接忽略。 |
exists key | 判斷指定鍵是否存在。 |
move key db | 將當前數據庫中指定的鍵Key移動到參數中指定的數據庫中。如果該Key在目標數據庫中已經存在,或者在當前數據庫中並不存在,該命令將不做任何操作並返回0。 |
rename key newkey | 爲指定指定的鍵重新命名,如果參數中的兩個Keys的命令相同,或者是源Key不存在,該命令都會返回相關的錯誤信息。如果newKey已經存在,則直接覆蓋。 |
renamenx key newkey | 如果新值不存在,則將參數中的原值修改爲新值。其它條件和RENAME一致。 |
persist key | 如果Key存在過期時間,該命令會將其過期時間消除,使該Key不再有超時,而是可以持久化存儲。 |
expire key seconds | 該命令爲參數中指定的Key設定超時的秒數,在超過該時間後,Key被自動的刪除。如果該Key在超時之前被修改,與該鍵關聯的超時將被移除。 |
expireat key timestamp | 該命令的邏輯功能和EXPIRE完全相同,唯一的差別是該命令指定的超時時間是絕對時間,而不是相對時間。該時間參數是Unix timestamp格式的,即從1970年1月1日開始所流經的秒數。 |
ttl key | 獲取該鍵所剩的超時描述。 |
randomkey | 從當前打開的數據庫中隨機的返回一個Key。 |
type key | 獲取與參數中指定鍵關聯值的類型,該命令將以字符串的格式返回。 |
2. 操作
-
keys/del/exists/move/rename/renamenx
127.0.0.1:6379> flushdb OK #添加String類型的數據 127.0.0.1:6379> set mykey 2 OK #添加List類型的數據 127.0.0.1:6379> lpush mylist a b c (integer) 3 #添加Set類型的數據 127.0.0.1:6379> sadd myset 1 2 3 (integer) 3 #添加Sorted-Set類型的數據 127.0.0.1:6379> zadd myzset 1 "one" 2 "two" (integer) 2 #添加Hash類型的數據 127.0.0.1:6379> hset myhash username "tom" (integer) 1 #根據參數中的模式,獲取當前數據庫中符合該模式的所有key,從輸出可以看出,該命令在執行時並不區分與Key關聯的Value類型 127.0.0.1:6379> keys my* 1) "myset" 2) "mykey" 3) "myzset" 4) "myhash" 5) "mylist" #刪除了兩個Keys 127.0.0.1:6379> del mykey mylist (integer) 2 #查看剛剛刪除的Key是否還存在,從返回結果看,mykey確實已經刪除了 127.0.0.1:6379> exists mykey (integer) 0 #查看一下沒有刪除的Key,以和上面的命令結果進行比較 127.0.0.1:6379> exists myset (integer) 1 #將當前數據庫中的myset鍵移入到ID爲1的數據庫中 127.0.0.1:6379> move myset 1 (integer) 1 #切換到ID爲1的數據庫 127.0.0.1:6379> select 1 OK #查看當前數據庫中的所有key 127.0.0.1:6379[1]> keys * 1) "myset" #在重新打開ID爲0的缺省數據庫 127.0.0.1:6379[1]> select 0 OK #清空數據庫 127.0.0.1:6379> flushdb OK #準備新的測試數據 127.0.0.1:6379> set mykey "hello" OK #將mykey改名爲mykey1 127.0.0.1:6379> rename mykey mykey1 OK #由於mykey已經被重新命名,再次獲取將返回nil 127.0.0.1:6379> get mykey (nil) #通過新的鍵名獲取 127.0.0.1:6379> get mykey1 "hello" #爲renamenx準備測試key 127.0.0.1:6379> set oldkey "hello" OK 127.0.0.1:6379> set newkey "world" OK #當新名稱不存在時纔會執行。由於newkey已經存在,因此該命令未能成功執行 127.0.0.1:6379> renamenx oldkey newkey (integer) 0 #查看newkey的值,發現它並沒有被renamenx覆蓋 127.0.0.1:6379> get newkey "world"
-
ttl/persist/expire/expireat
127.0.0.1:6379> flushdb OK #準備測試數據,將該鍵的超時設置爲100秒 127.0.0.1:6379> set mykey "hello" ex 100 OK #通過ttl命令查看還剩多少秒 127.0.0.1:6379> ttl mykey (integer) 97 #立刻執行persist命令,該存在超時的鍵變成持久化的鍵,即將該Key的超時去掉 127.0.0.1:6379> persist mykey (integer) 1 #ttl的返回值告訴我們,該鍵已經沒有超時了 127.0.0.1:6379> ttl mykey (integer) -1 #爲後面的expire命令準備數據 127.0.0.1:6379> del mykey (integer) 1 127.0.0.1:6379> set mykey "hello" OK #設置該鍵的超時被100秒 127.0.0.1:6379> expire mykey 100 (integer) 1 #用ttl命令看當前還剩下多少秒,從結果中可以看出還剩下96秒 127.0.0.1:6379> ttl mykey (integer) 96 #重新更新該鍵的超時時間爲20秒,從返回值可以看出該命令執行成功 127.0.0.1:6379> expire mykey 20 (integer) 1 #再用ttl確認一下,從結果中可以看出被更新了 127.0.0.1:6379> ttl mykey (integer) 17 #立刻更新該鍵的值,以使其超時無效。 127.0.0.1:6379> set mykey "world" OK #從ttl的結果可以看出,在上一條修改該鍵的命令執行後,該鍵的超時也無效了 127.0.0.1:6379> ttl mykey (integer) -1
-
type/randomkey
127.0.0.1:6379> del mykey (integer) 1 #添加不同類型的測試數據 127.0.0.1:6379> set mykey 2 OK 127.0.0.1:6379> lpush mylist a b c (integer) 3 127.0.0.1:6379> sadd myset 1 2 3 (integer) 3 127.0.0.1:6379> zadd myzset 1 "one" 2 "two" (integer) 2 127.0.0.1:6379> hset myhash username "tom" (integer) 1 #分別查看數據的類型 127.0.0.1:6379> type mykey string 127.0.0.1:6379> type mylist list 127.0.0.1:6379> type myset set 127.0.0.1:6379> type myzset zset 127.0.0.1:6379> type myhash hash #返回數據庫中的任意鍵 127.0.0.1:6379> randomkey "oldkey" #清空當前打開的數據庫 127.0.0.1:6379> flushdb OK #由於沒有數據了,因此返回nil 127.0.0.1:6379> randomkey (nil)
五、事務
1. 概述
和其它數據庫一樣,Redis作爲NoSQL數據庫也同樣提供了事務機制。在Redis中,MULTI/EXEC/DISCARD/WATCH這四個命令是我們實現事務的基石。Redis中事務的特徵:
1). 在事務中的所有命令都將會被串行化的順序執行,事務執行期間,Redis不會再爲其它客戶端的請求提供任何服務,從而保證了事物中的所有命令被原子的執行。
2). 和關係型數據庫中的事務相比,在Redis事務中如果有某一條命令執行失敗,其後的命令仍然會被繼續執行。
3). 我們可以通過MULTI命令開啓一個事務,有關係型數據庫開發經驗的人可以將其理解爲"BEGIN TRANSACTION"語句。在該語句之後執行的命令都將被視爲事務之內的操作,最後我們可以通過執行EXEC/DISCARD命令來提交/回滾該事務內的所有操作。這兩個Redis命令可被視爲等同於關係型數據庫中的COMMIT/ROLLBACK語句。
4). 在事務開啓之前,如果客戶端與服務器之間出現通訊故障並導致網絡斷開,其後所有待執行的語句都將不會被服務器執行。然而如果網絡中斷事件是發生在客戶端執行EXEC命令之後,那麼該事務中的所有命令都會被服務器執行。
5). 當使用Append-Only模式時,Redis會通過調用系統函數write將該事務內的所有寫操作在本次調用中全部寫入磁盤。然而如果在寫入的過程中出現系統崩潰,如電源故障導致的宕機,那麼此時也許只有部分數據被寫入到磁盤,而另外一部分數據卻已經丟失。Redis服務器會在重新啓動時執行一系列必要的一致性檢測,一旦發現類似問題,就會立即退出並給出相應的錯誤提示。此時,我們就要充分利用Redis工具包中提供的redis-check-aof工具,該工具可以幫助我們定位到數據不一致的錯誤,並將已經寫入的部分數據進行回滾。修復之後我們就可以再次重新啓動Redis服務器了。
2. 命令列表
命令 | 解釋 |
---|---|
multi | 用於標記事務的開始,其後執行的命令都將被存入命令隊列,直到執行EXEC時,這些命令纔會被原子的執行。 |
exec | 執行在一個事務內命令隊列中的所有命令,同時將當前連接的狀態恢復爲正常狀態,即非事務狀態。如果在事務中執行了WATCH命令,那麼只有當WATCH所監控的Keys沒有被修改的前提下,EXEC命令才能執行事務隊列中的所有命令,否則EXEC將放棄當前事務中的所有命令。 |
discard | 回滾事務隊列中的所有命令,同時再將當前連接的狀態恢復爲正常狀態,即非事務狀態。如果WATCH命令被使用,該命令將UNWATCH所有的Keys。 |
3. 操作
1. 事務被正常執行
#在當前連接上啓動一個新的事務
127.0.0.1:6379> multi
OK
#執行事務中的第一條命令,從該命令的返回結果可以看出,該命令並沒有立即執行,而是存於事務的命令隊列
127.0.0.1:6379> incr t1
QUEUED
#又執行一個新的命令,從結果可以看出,該命令也被存於事務的命令隊列
127.0.0.1:6379> incr t2
QUEUED
#執行事務命令隊列中的所有命令,從結果可以看出,隊列中命令的結果得到返回
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
#只有當提交事務後,在其他連接中才能看到變化
2. 事務中存在失敗的命令
#開啓一個新的事務
127.0.0.1:6379> multi
OK
#設置鍵a的值爲string類型的3
127.0.0.1:6379> set a 3
QUEUED
#從鍵a所關聯的值的頭部彈出元素,由於該值是字符串類型,而lpop命令僅能用於List類型,因此在執行exec命令時,該命令將會失敗
127.0.0.1:6379> lpop a
QUEUED
#再次設置鍵a的值爲字符串4
127.0.0.1:6379> set a 4
QUEUED
#獲取鍵a的值,以便確認該值是否被事務中的第二個set命令設置成功
127.0.0.1:6379> get a
QUEUED
#從結果中可以看出,事務中的第二條命令lpop執行失敗,而其後的set和get命令均執行成功,這一點是Redis的事務與關係型數據庫中的事務之間最爲重要的差別
127.0.0.1:6379> exec
1) OK
2) (error) ERR Operation against a key holding the wrong kind of value
3) OK
4) "4"
3. 回滾事務
#爲鍵t2設置一個事務執行前的值
127.0.0.1:6379> set t2 tt
OK
#開啓一個事務
127.0.0.1:6379> multi
OK
#在事務內爲該鍵設置一個新值
127.0.0.1:6379> set t2 ttnew
QUEUED
#放棄事務
127.0.0.1:6379> discard
OK
#查看鍵t2的值,從結果中可以看出該鍵的值仍爲事務開始之前的值
127.0.0.1:6379> get t2
"tt"
六、主從複製Replication
1. 概述
在Redis中配置Master-Slave模式非常簡單,Redis中主從複製的特點和優勢:
1). 同一個Master可以同步多個Slaves。
2). Slave同樣可以接受其它Slaves的連接和同步請求,可以有效的分載Master的同步壓力,所以可以將Redis的Replication架構視爲圖結構。
3). Master Server是以非阻塞的方式爲Slaves提供服務,所以在Master-Slave同步期間,客戶端仍然可以提交查詢或修改請求。
4). Slave Server同樣是以非阻塞的方式完成數據同步,在同步期間,如果有客戶端提交查詢請求,Redis則返回同步之前的數據。
5). 爲了分載Master的讀操作壓力,Slave服務器可以爲客戶端提供只讀操作的服務,寫服務仍然必須由Master來完成。即便如此,系統的伸縮性還是得到了很大的提高。
6). Master可以將數據保存操作交給Slaves完成,從而避免了在Master中要有獨立的進程來完成此操作。
2. 配置
步驟:
-
同時啓動兩個Redis服務器,可以考慮在同一臺機器上啓動兩個Redis服務器,分別監聽不同的端口,如6379和6380
將配置文件拷貝兩份,並修改端口號
啓動服務器:
$ redis-server 6379.conf #master主服務器 $ redis-server 6380.conf #slave從服務器
-
連接slave服務器,並執行如下命令:
$ redis-cli -p 6380 #連接從服務器,slave端口號爲6380 127.0.0.1:6380> slaveof 127.0.0.1 6379 #配置主從關係,指定master的主機地址和端口號 OK
上面的方式只是保證了在執行slaveof命令之後,redis_6380成爲了redis_6379的slave,一旦服務(redis_6380)重新啓動之後,他們之間的複製關係將終止。
如果希望長期保證這兩個服務器之間的Replication關係,可以在redis_6380的配置文件中做如下修改:
$ vi 6380.conf slaveof 127.0.0.1 6379
這樣就可以保證Redis_6380服務程序在每次啓動後都會主動建立與Redis_6379的Replication連接了。
七、持久化
1. 概述
Redis提供的持久化方式:
-
RDB
該機制是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。
-
AOF
該機制將以日誌的形式記錄服務器所處理的每一個寫操作,在Redis服務器啓動之初會讀取該文件來重新構建數據庫,以保證啓動後數據庫中的數據是完整的。
2. RDB
Redis Database:通過單文件的方式來持久化
RDB是默認的持久化方式,默認存儲在啓動redis服務器時所在當前目錄下的dump.rdb文件中,一般都會修改存儲在一個固定的目錄中
編輯配置文件:
$ vi myredis.conf
dbfilename dump.rdb #持久化文件的名稱
#dir ./ #持久化文件的目錄,默認爲執行redis-server命令時所在的當前目錄
dir /home/soft01/software/dump/ #修改存儲位置爲一個固定的目錄
持久化的時機:
-
在數據庫關閉時會持久化(需要注意的是在數據庫宕機時不會生成,數據可能會丟失)
-
滿足特定條件時會持久化,編輯配置文件:
$ vi myredis.conf save 900 1 #在900秒內,只要有1個key發生變化,就會dump持久化 save 300 10 save 60 10000
優缺點:
- 缺點:可能會丟失數據
- 優點:效率比較高
3. AOF
Append Only File:通過操作日誌的方式來持久化
編輯配置文件:
$ vi myredis.conf
appendonly yes #開啓aof模式的持久化
appendfilename "appendonly.aof" #aof的持久化文件
appendfsync everysec #每一秒進行一次持久化操作,可取值:always、everysec、no
dir /home/soft01/software/dump/ #持久化文件的目錄,與RDB相同
注:可以直接查看生成的appendonly.aof文件,可以認爲是一個日誌文件
優缺點:
- 缺點:效率比較差
- 優點:丟失數據量比較少
八、Java訪問Redis
1. 使用Jedis
Jedis是一個封裝了redis的java客戶端,集成了redis的一些命令操作,並提供了連接池管理功能
步驟:
-
添加依賴
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
-
基本用法
public void test01(){ //獲取jedis的連接 Jedis jedis=new Jedis("192.168.19.37",6379); //驗證 jedis.auth("itany"); //操作redis //jedis.set("name","tom"); //jedis.set("password","123","nx"); //System.out.println(jedis.get("name")); //jedis.lpush("mylist","jack","alice","mike"); //System.out.println(jedis.lrange("mylist",0,1)); //jedis.sadd("myset","aaa","bbb","ccc"); //System.out.println(jedis.smembers("myset")); //System.out.println(); // //jedis.zadd("myzset",10,"a"); //jedis.zadd("myzset",20,"b"); //jedis.zadd("myzset",15,"c"); //System.out.println(jedis.zrange("myzset",0,-1)); //System.out.println(); // //jedis.hset("user","name","alice"); //jedis.hset("user","age","21"); //Set<String> keys = jedis.hkeys("user"); //for (String key:keys){ // System.out.println(key+"="+jedis.hget("user",key)); //} Set<String> keys = jedis.keys("*"); System.out.println(keys); //關閉連接 jedis.close(); }
2. 使用Spring Data Redis
簡稱SDR,在Spring應用中讀寫Redis數據庫更簡單
基於jedis