Redis(REmote DIctionary Server) Redius 為非關聯式的鍵值資料庫(Map) 支援的資料型別:
字串型態(String) 包含字串(JSON,BASE64,二進位資料),整數,浮點數
雜湊(Hash)型態 巢狀 key-value,無順序性
列表(List)型態
集合(Set)型態
有序集合(Sorted Set)型態 Zset
指令和 key 型別要對,不然會噴 Exception
功能特性
Redis 將所有資料都儲存在記憶體 裡讀寫速度比硬碟快上許多
Redis 提供了持久化的支援記憶體的資料以非同步的方式輸出到硬碟裡
可以幫每個 key 設定存活時間 (Time To Live, TTL),常用於快取和佇列
提供了十幾種不同程式語言的 API
安裝
Redis官方並不對Windows進行安裝支援的開發,但微軟的Open Technologies Inc.還是發佈了一個可以在Windows上執行Redis的分支,目前最新版只到3.2版,請參考:
https://github.com/MicrosoftArchive/redis/releases
根據次版本編號(也就是第一個小數點數字)為偶數的版本是穩定版(Stable),奇數版本為非穩定版
變成手動後要下指令開,關閉視窗即關閉
1 redis -server C:\redis.windows.conf
也可以寫腳本,先開一文字文件,再輸入指令後把檔名改成批次檔(.bat)
1 2 @echo off redis-server C:\Redis\redis.windows.conf --appendonly yes
1 2 @echo off redis-cli shutdown
開啟執行批次檔後可以使用 CMD 來下指令
1 2 3 4 5 6 7 8 redis-cli IP:6379> ping PONG IP:6379> set Hello REdis OK IP:6379> get Hello "REdis"
使用 set , get 方式設定 key,value 輸入資料後可以搭配使用 redis 的圖形化介面來看存取的資料https://github.com/qishibo/AnotherRedisDesktopManager
預設為 16 個儲存空間如需要切換的話需下指令,不切換預設為 db0
與 MySQL 不同,不開放,所以無帳號密碼設定上的需要(扮演暫存,快取角色)
操作資料
Redis 會根據新增資料使用的指令,自動推斷型別
預設初始值為 null,key 為唯一,如同名會覆蓋
字串操作指令 :
1 2 3 4 5 6 GET key : SET key newValue : DEL key :
在 Java 中操作指令 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Jedis jedis = new Jedis ("localhost" , 6379 );jedis.set("key" ,"value" ); jedis.get("key" ); jedis.append("key" ,"value2" ); jedis.strlen("key" ); jedis.getrange("key" ,2 ,5 ); jedis.getrange("key" ,-3 ,-1 );
多筆資料處理
1 2 3 jedis.mset("key1" , "value1" , "key2" , "value2" , "key3" , "value3" ); List<String> data = jedis.mget("key1" , "key2" , "key3" ); for (String str : data)
處理整數資料
1 2 3 4 5 6 for (int i = 1 ; i <= 100 ; i++) { jedis.incr("num" ); } jedis.decr("num" );
你的 value 必須為數字格式才能使用以上方法
處理位元資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 jedis.set("foo" , "bar" ); System.out.println(jedis.getbit("foo" , 6 )); jedis.setbit("foo" , 6 , false ); jedis.setbit("foo" , 7 , true ); System.out.println(jedis.get("foo" )); jedis.set("foo1" , "bar" ); jedis.set("foo2" , "aar" ); jedis.bitop(BitOP.OR, "result" , "foo1" , "foo2" ); System.out.println(jedis.get("result" ));
List資料
List 如同 LinkedList,或是可視為佇列或堆疊進行操作,因為可以進行 List 的左右兩端的加入與移除,或是取得某一部份內容,但搭配索引值存取的效能表現就較不理想
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 jedis.lpush("customers" , "David" , "James" , "Vincent" , "Ben" , "Ron" , "George" , "Howard" ); jedis.lpop("customers" ); jedis.rpush("customers" , "Jerry" , "Joe" , "Smith" ); List<String> range1 = jedis.lrange("customers" , 3 , 6 ); for (String customer : range1) System.out.println(customer); jedis.llen("customers" ); jedis.ltrim("customers" , 3 , 6 ); List<String> range2 = jedis.lrange("customers" , 0 , jedis.llen("customers" ) - 1 ); for (String customer : range2) System.out.println(customer); jedis.linsert("customers" , LIST_POSITION.BEFORE, "David" , "Jedis" ); List<String> range3 = jedis.lrange("customers" , 0 , jedis.llen("customers" ) - 1 ); for (String customer : range3) System.out.println(customer);
Hash資料
目的是讓 Redis 可以如同關聯式資料庫(表格-欄位)的存取對應關係
Hash 型態也是一種 key-value 結構,儲存欄位與對應的值,但值只能是字串資料,不支援其它型態,因此不能做巢狀結構 (Redis 所有資料型態都不支援巢狀資料結構)
Hash 型態很適合用來儲存物件,利用物件所屬類別與 ID 做為 key,而實體變數名稱做為欄位,而欄位值存著實體變數的值
可在購物車使用
1 2 3 4 jedis.hset("pen:1" , "brand" , "SKB" ); jedis.hset("pen:1" , "price" , "10" ); jedis.hget("pen:1" , "brand" ); jedis.hget("pen:1" , "price" );
Set
重複資料無法放入,資料為唯一
key 之間還能進行聯集、交集與差集等運算 (如文章分類標籤)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 jedis.sadd("post:1:tags" , "Java" ); jedis.sadd("post:2:tags" , "Java" , "Servlet" ); jedis.sadd("post:3:tags" , "Java" , "Servlet" , "JSP" ); jedis.sadd("tag:Java:posts" , "2" , "1" , "3" ); jedis.sadd("tag:Servlet:posts" , "3" , "2" ); jedis.sadd("tag:JSP:posts" , "3" ); for (String str : jedis.smembers("post:3:tags" )) { System.out.println(str); } jedis.sismember("post:2:tags" , "JSP" ); jedis.sdiff("A集合" ,"B集合" ); jedis.sinter("A集合" ,"B集合" ); jedis.sunion("A集合" ,"B集合" ); jedis.sadd("candidate" , "David" , "James" , "Vincent" , "Peter" , "Ron" , "George" ); System.out.println(jedis.srandmember("candidate" )); System.out.println(jedis.srandmember("candidate" , 3 ));
Zset
List 是 Linked 結構,所以對兩端資料存取效率極高,但對中間元素處理較慢,適合用在新的資料或最舊的資料(兩端)存取
Zset 非 Linked 結構,即使是取中間元素資料速度也很快
List 要調整某個元素位置效能表現不佳,但 Zset 表現極佳(透過調整元素連結的分數即可)
Zset 比起 List 更耗費記憶體的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 Map<String, Double> scores1 = new HashMap <>(); scores1.put("David" , new Double (100 )); scores1.put("James" , new Double (85 )); scores1.put("Ron" , new Double (67 )); scores1.put("Vincent" , new Double (72 )); scores1.put("George" , new Double (87 )); scores1.put("Howard" , new Double (75 )); scores1.put("Peter" , new Double (80 )); Map<String, Double> scores2 = new HashMap <>(); scores2.put("David" , new Double (90 )); scores2.put("James" , new Double (77 )); scores2.put("Ron" , new Double (78 )); scores2.put("Vincent" , new Double (68 )); scores2.put("George" , new Double (95 )); scores2.put("Howard" , new Double (81 )); scores2.put("Peter" , new Double (72 )); jedis.zadd("scores1" , scores1); jedis.zadd("scores2" , scores2); jedis.zadd("scores1" , 92 , "Vincent" ); jedis.zscore("scores1" , "Vincent" ); jedis.zrange("scores1" , 1 , -1 ); jedis.zrangeByScore("scores1" , "80" , "(100" ); jedis.zrevrangeByScore("scores1" , "100" , "0" , 0 , 3 ); jedis.zincrby("scores1" , 8 , "Peter" ); jedis.zrank("scores1" , "David" ); jedis.zrevrank("scores1" , "David" ); ZParams zp = new ZParams ();jedis.zinterstore("scoresinter" , zp.aggregate(Aggregate.SUM), "scores1" , "scores2" ); System.out.println(jedis.zrevrange("scoresinter" , 0 , -1 ));
JSON 資料格式
JSON(JavaScript Object Notation)為一種輕量級的資料交換語言,以文字為基礎而讓人容易閱讀理解,在 WEB 的資料傳輸上,佔有相當重要的地位
可以讓不同的程式語言可以互相進行資料傳輸的交換使用,也實現了以文字形式對物件進行序列化
XML 也是類似的概念,但因為 XML 是一種完整標記語言,因此在程式撰寫判讀上比起 JSON 過於笨重與較多心力,故現今瀏覽器解析、手機資料交換都採用較輕量的 JSON 以取得最佳效能
JSON 是一種以鍵值(key-value)的方式存取資料:
1 2 3 4 { “myKey”: myValue} [ { “myKey”: myValue} , { “myKey2”: myValue2} ]
Java SE 沒有包含 JSON API,要 import jar 檔
Base64 資料格式
Java 8 在 java.util 套件新增了 Base64 類別,即可使用標準 API 進行操作:
1 2 3 4 5 6 String encode = Base64.getEncoder().encodeToString("Hello World!" .getBytes("UTF-8" ));System.out.println(encode); byte [] decode = Base64.getDecoder().decode(encode);System.out.println(new String (decode, "UTF-8" ));
不鼓勵存取大量資料時使用,因為效能差
3 bytes to 4 characters,資料變長,傳輸時間長
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class TestBase64 { public static void main (String[] args) throws IOException { File file = new File ("FC_Bayern.png" ); FileInputStream fis = new FileInputStream (file); byte [] pic = new byte [fis.available()]; fis.read(pic); fis.close(); String base64str = Base64.getEncoder().encodeToString(pic); System.out.println(base64str); byte [] fromBase64str = Base64.getDecoder().decode(base64str); FileOutputStream fos = new FileOutputStream ("fromBase64str.png" ); fos.write(fromBase64str); fos.flush(); fos.close(); } }
Redis 交易機制
交易裡的所有指令都是循序執行,而交易執行期間,Redis 就不會再接受其它用戶端的請求提供任何服務,以確保原子性(A)執行
與關聯式資料庫不同,若是其中有指令執行失敗,Redis 會繼續執行後續的指令 (沒有 rollback 機制)
交易開啟之前,若通訊發生故障,則所有交易指令都不會執行;但若是已經執行 EXEC 指令之後發生通訊故障,則指令都會被 Redis 執行
Redis 資料存活機制 TTL(Time To Live)
在開發功能時,可能會遇到一些有時效性的資料處理,例如限時優惠、快取機制,或是驗證信件點擊處理等,過了一定時間就要做資料刪除的動作,而 Redis 就提供了這樣的功能,可以對 key 設定存活時間,只要指定的時間到期,由 Redis 自動刪除
指令 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 jedis.set("test" , "Hello" ); jedis.expire("test" , 10 ); jedis.ttl("test" ); jedis.pttl("test" ); jedis.persist("test" ); jedis.expireat("test" , 10 ); jedis.pexpireat("test" , 10 );
Redis 持久化機制
RDB
官方的設定檔redis.conf裡就預置了三個RDB啟動快照的條件:
save 900 1 (單位:秒/資料量)
save 300 10
save 60 10000
RDB 優點 :
使用 RDB 對整個 Redis 資料庫來說就是一個檔案,因此在進行資料恢復時,可以做到較輕鬆的處理
RDB 採用子程序處理快照動作,這對 Redis 服務來說執行效率較佳
RDB 缺點 :
若是在 RDB 持久化未進行的期間發生當機等中斷服務狀態時,資料都將會遺失
若是一次要快照的資料較大時,會影響到 Redis 程序的運作
AOF
AOF設定條件 (2)為預設設定:
1. appendfsync always
2. appendfsync everysec
3. appendfsync no
AOF 優點:
帶來更高的資料持久性與安全性,因為是採取同步機制進行儲存
因為採用 append 機制,所以寫入中發生當機現象,也不會破壞原有的內容,也有 redis-check-aof 工具可以協助解決資料一致性問題
AOF 包含一個完整記錄檔記錄了所有的修改操作,也可以透過 AOF 完成資料重建的動作
AOF 缺點:
對相同的資料量來說,AOF 的檔案會比 RDB 檔案來得大
因為採用同步方式,所以 AOF 在執行的效能上慢於 RDB 機制