Categories
程式開發

Redis-技術專題-Jedis實戰入門


Redis是一個開源,高級的鍵值存儲和一個適用的解決方案,用於構建高性能,可擴展的Web應用程序。本文將概要介紹Redis的特性和語法,並以實例代碼的形式介紹如何通過Jedis在java語言環境下控制Redis,幫助各位讀者快速入門。

NoSQL概述

Redis是NoSQL數據庫的代表之一,那什麼是NoSQL?

NoSQL = not only SQL,即非關係型數據庫。

為什麼使用NoSQL?

和傳統的關係型數據庫相比,NoSQL具有以下的優勢:

High Performance:高並發讀寫;Huge Storage: 海量數據的高效存儲和訪問;High Scalability & High Availability:高可擴展和高可用性

NoSQL的分類:

Key-Value,如Redis,快速查詢,但是數據存儲缺少結構化;列存儲,如HBase, 擴展性強,查找速度快,但是功能局限;文檔數據庫,如MongoDB,數據格式靈活,查詢性能不高,缺少統一的查詢語法;圖形數據庫,如InfoGrid,基於圖的算法,但是不容易做分佈式的查詢;

Redis概述

Redis是一個開源,高性能的鍵值對數據庫, 其優點包括:

異常快 :Redis非常快,每秒可執行大約110000次的設置(SET)操作,每秒大約可執行81000次的讀取/獲取(GET)操作。支持豐富的數據類型 :Redis支持開發人員常用的大多數數據類型,例如列表,集合,排序集和散列等等。這使得Redis很容易被用來解決各種問題,因為我們知道哪些問題可以更好使用地哪些數據類型來處理解決。操作具有原子性 : 所有Redis操作都是原子操作,這確保如果兩個客戶端並發訪問,Redis服務器能接收更新的值。多實用工具 : Redis是一個多實用工具,可用於多種用例,如:緩存;任務隊列;網站統計;數據過期處理;應用排行榜;分佈式集群的Session分離;

Redis與其他鍵值存儲系統

Redis是鍵值數據庫系統的不同進化路線,它的值可以包含更複雜的數據類型,可在這些數據類型上定義原子操作。 Redis是一個內存數據庫,但在磁盤數據庫上是持久的,因此它代表了一個不同的權衡,在這種情況下,在不能大於存儲器(內存)的數據集的限制下實現非常高的寫和讀速度。內存數據庫的另一個優點是,它與磁盤上的相同數據結構相比,複雜數據結構在內存中存儲表示更容易操作。因此,Redis可以做很少的內部複雜性。

Redis的安裝和使用

Redis的安裝是否簡單,在Ubuntu上安裝Redis,打開終端並鍵入以下命令即可

sudo apt-get update
sudo apt-get install redis-server

啟動服務器:redis-server啟動客戶端:redis-cli

如果是Windows環境下,則參照以下文章:

http://download.csdn.net/download/fengxinyixiao/9860813http://blog.csdn.net/joyhen/article/details/47358999

Jedis入門

Jedis是Redis官網首選的Java客戶端開發包.

Redis-技術專題-Jedis實戰入門 1

Jedis是Redis官網首選的Java客戶端開發包

其GItHub地址為:

https://github.com/xetorthio/jedis

在Maven中,添加如下依賴即可使用:


redis.clients
jedis
2.9.0
jar
compile

以下是官網是上給出的示例代碼,連接本地Redis,進行操作.

@Test
public void ConnectionTest(){
//1. Connecting to Redis server on localhost
Jedis jedis = new Jedis("localhost");
System.out.println("Connection to server sucessfully");
//2. set the data in redis string
jedis.set("username", "Roxin");
//3. Get the stored data and print it
System.out.println("Stored string in redis:: "+ jedis.get("username"));
//4. Close the Redis connection;
jedis.close();
}

其中通過調用set方法來設置鍵值對,通過get方法獲取鍵值對。

除此之外,Jedis還提供連接池的方式控制連接

@Test
public void ConnectionPoolTest(){
//连接池设定
JedisPoolConfig config = new JedisPoolConfig();
//设定最大连接数
config.setMaxTotal(30);
//设置最大空闲连接数
config.setMaxIdle(10);
//创建连接池
JedisPool jedisPool = new JedisPool(config, "127.0.0.1");
//获得服务资源
Jedis jedis = jedisPool.getResource();
jedis.select(1);
jedis.set("username", "Roxin By Jedis Pool");
System.out.println(jedis.get("username"));
jedis.close();
jedisPool.close();
}

Redis的數據類型

Redis中的數據類型有:

字符串(String)列表(list)有序集合(sorted set)散列(hash)集合(set)

無論哪種數據類型都需要為其設定鍵值Key,設置Key的注意點:

不要太長(<1024字節);不要太短,有可讀性;統一命名規範;

Redis中的字符串是一個字節序列。 Redis中的字符串是二進制安全的,這意味著它們的長度不由任何特殊的終止字符決定。因此,可以在一個字符串中存儲高達512兆字節的任何內容。

除了上面提到的set/get方法,還有其他命令如下表:

Redis-技術專題-Jedis實戰入門 2

雜湊

相當於Map,在Redis中,每個哈希(散列)可以存儲多達4億個鍵-值對。

Jedis示例代碼如下

@Test
public void HashTest(){
Jedis jedis = jedisPool.getResource();
String hashKey = "hashKey";
//hset设置一个键值对
jedis.hset(hashKey,"user","Roxin");
HashMap map = new HashMap();
for (int i = 0; i < 10; i++) { map.put("field"+i,"value"+i); } //设置多个键值对 jedis.hmset(hashKey,map); //获得键值对的个数 Long hlen = jedis.hlen(hashKey); System.out.println("Hash Size in redis:: "+hlen); assert hlen==11; //得到全部键值对 List user = jedis.hmget(hashKey, "user"); System.out.println("Stored string in redis:: "+ user); assert user.get(0).equals("Roxin"); //删除键值 jedis.del(hashKey); jedis.close(); }

Redis關於Hash類型的常見命令如下表:

Redis-技術專題-Jedis實戰入門 3

清單

Redis列表只是字符串列表,按插入順序排序。可以在列表的頭部或尾部添加Redis列表中的元素。

列表的最大長度為2^32 - 1個元素(即4294967295,每個列表可存儲超過40億個元素)。

Jedis中示例代碼如下

@Test
public void ListTest(){
Jedis jedis = jedisPool.getResource();
String listKey = "LISTKEY";
for (int i = 0; i < 10; i++) { //从头插入一个元素 jedis.lpush(listKey,"L-value"); } List list = jedis.lrange(listKey, 0, -1);//从第一个到最后一个,负数代表倒数第几个 assert list.size() == 10; assert "L-value".equals(jedis.rpop(listKey));//从尾部取出一个元素 assert 9==jedis.llen(listKey); jedis.rpush(listKey,"R-valure");//从尾部加入一个元素 jedis.lrem(listKey,2,"L-value");//删除从左数2两个"L-value"元素 jedis.lrem(listKey,0,"L-value"); //0表示删除全部"L-value"元素 assert "R-valure".equals(jedis.lpop(listKey));//从头部加入一个元素 jedis.del(listKey); jedis.close(); }

Redis中關於list的命令如下表:

Redis-技術專題-Jedis實戰入門 4

需要特別說明下:

rpoplpush源目的地

刪除列表中的最後一個元素,將其附加到另一個列表並返回,在消息隊列中,可以用於消息備份:當消息被發布後,一個消息從主消息隊列中被取出,被放入到緩存隊列中,當確認發生成功之後,再將其徹底刪除,如果發送不成功,就恢復該消息。

Redis-技術專題-Jedis實戰入門 5

Redis集合是唯一字符串的無序集合。唯一值表示集合中不允許鍵中有重複的數據。

在Redis中設置添加,刪除和測試成員的存在(恆定時間O(1),而不考慮集合中包含的元素數量)。列表的最大長度為2^32 - 1個元素(即4294967295,每組集合超過40億個元素)。

存儲Set的使用場景:

跟踪唯一性數據用於維護數據對象之間的關聯關係;

Jedis的代碼示例:

@Test
public void SetTest(){
Jedis jedis = jedisPool.getResource();
String setKey1 = "SETKEY-1";
for (int i = 0; i < 10; i++) { //添加一个元素 jedis.sadd(setKey1,"value-"+i); } assert 10 == jedis.scard(setKey1); //获得元素个数 jedis.sadd(setKey1,"value-1");//添加重复的元素将失效 assert 10 == jedis.scard(setKey1); String s= jedis.srandmember(setKey1);//随机获取一个元素 assert jedis.sismember(setKey1,s);//是否为集合成员 String setKey2 = "SETKEY-2"; for (int i = 1; i < 11; i++) { jedis.sadd(setKey2,"value-"+i); } assert jedis.sdiff(setKey1,setKey2).size() == 1;//补集 assert jedis.sinter(setKey1,setKey2).size() == 9;//交集 assert jedis.sunion(setKey1,setKey2).size() == 11;//并集 jedis.del(setKey1,setKey2); jedis.close(); }

Redis中關於Set的命令如下表:

Redis-技術專題-Jedis實戰入門 6

排序集

Redis可排序集合類似於Redis集合,是不重複的字符集合。不同之處在於,排序集合的每個成員都與分數相關聯,這個分數用於按最小分數到最大分數來排序的排序集合。雖然成員是唯一的,但分數值可以重複。

Sorted-Set的使用場景:

大型在線遊戲的積分排名;構建索引數據;

Jedis中的示例:

@Test
public void SortedSetTest(){
Jedis jedis = jedisPool.getResource();
String sortedSetKey = "SORTEDSETKEY";
for (int i = 0; i < 10; i++) { //添加一个元素 jedis.zadd(sortedSetKey,i*10,"v-"+i); } assert 10 == jedis.zcard(sortedSetKey);//获得集合中元素个数 assert 20 == (jedis.zscore(sortedSetKey,"v-2"));//获得集合中元素对应的分数 Set set = jedis.zrange(sortedSetKey, 0, -2);//从第一个到倒数第二个 assert 9 == set.size() ; assert !set.contains("v-9"); jedis.zincrby(sortedSetKey,20,"v-1");//让元素的分数增长20 assert 30 == jedis.zscore(sortedSetKey,"v-1"); assert 3 == jedis.zcount(sortedSetKey,20,30);//获得分数段中元素个数 jedis.del(sortedSetKey); jedis.close(); }

Keys的通用操作

Jedis中關於鍵值操作的實例:

@Test
public void KeyTest(){
Jedis jedis = jedisPool.getResource();
String key = "TESTKEY-1";
String key2 = "TESTKEY-2";
jedis.set(key2,"");//设置键值
jedis.rename(key2,key);//键值重命名
System.out.println("Key Type:"+jedis.type(key));//键值的类型
assert jedis.exists(key);//键值是否存在
jedis.expire(key,1);//设置键值过期时间
assert 1 == jedis.ttl(key);//查看键值过期时间
try {
Thread.sleep(2000);//睡眠2s
} catch (InterruptedException e) {
e.printStackTrace();
}
assert !jedis.exists(key);//键值已过期,不存在
}

Redis中關於鍵值的其他命令:

Redis-技術專題-Jedis實戰入門 7

KEYS pattern 查找與指定模式匹配的所有鍵:

keys * 查看所有的key;keys xx? 模糊匹配key;

Redis的特性

多數據

提供16個數據庫(0-15),默認為0號數據庫,可是通過select index選擇。

事務

和關係型數據庫一樣,Redis也提供事務性操作:

DISCARD 丟棄在MULTI之後發出的所有命令(放棄事務,回滾)EXEC 執行MULTI後發出的所有命令(提交事務)MULTI 標記事務塊的開始(開始事務)UNWATCH 取消WATCH 命令對所有key 的監視。 WATCH key [key …] 監視給定的鍵以確定MULTI / EXEC塊的執行

Redis中示例代碼如下:

@Test
public void TransactionTest(){
//获得服务资源
Jedis jedis = jedisPool.getResource();
jedis.select(1);
Transaction transaction = jedis.multi();//开启事务
transaction.set("username", "Roxin in transaction1");
System.out.println(transaction.get("username"));
transaction.exec();//提交事务
System.out.println(jedis.get("username"));
transaction = jedis.multi();//开启事务
transaction.set("username", "Roxin in transaction2");
System.out.println(transaction.get("username"));
transaction.discard();//撤销事务
System.out.println(jedis.get("username"));
jedis.close();
}

Redis持久化

Redis是一個內存數據庫,但在磁盤數據庫上是持久化的,持久化的方式分為兩種:

RDB:默認方式,定時將內存數據集快照寫入磁盤;AOF:以日誌的方式,記錄所有操作;

RDB

優勢

數據只存在一個文件中,便於數據歸檔和整理;多線程啟動,性能好;

劣勢

如果在兩次快照寫操作之間出現問題,將無法回复期間的數據;多線程啟動的時候,可能會有停頓;

配置文件為Redis按照目錄下的redis.conf:

Redis-技術專題-Jedis實戰入門 8

redis.conf 保存頻率的設施

這是配置文件設置內存快照寫入磁盤的條件

# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
save 900 1
save 300 10
save 60 10000

數據文件被定義為dump.rdb,保存路徑為Redis的按照路徑。

# The filename where to dump the DB
dbfilename dump.rdb

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./

Redis-技術專題-Jedis實戰入門 9

Redis數據文件,只有一個數據文件

AOF

優勢:

更高的數據安全性,有三種數據同步策略:日誌是追加(append)模式,即使有宕機,也不會用問題。如果是數據寫入一半出現問題,可以使用redis-check-aof,恢復數據一致;日誌自動重寫,以防止日誌過大;日誌格式清楚明了,可用於數據重建;

劣勢:

文件要更大;運行效率更低;

配置文件中關於AOF的配置:

Redis-技術專題-Jedis實戰入門 10

關於AOF的配置

默認不使用;

日誌文件為 appendonly.aof

# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"

上面提高的三種同步策略;

# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec",If unsure, use "everysec".

# appendfsync always
appendfsync everysec
# appendfsync no