一、Redis簡介
redis是一個高性能的key-value非關系數據庫,它可以存鍵(key)與5種不同類型的值(value)之間的映射(mapping),支持存儲的value類型包括:String(字符串)、list(鏈表)、set(集合)、zset(有序集合)和hash(散列表)。這些收據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,為了保證效率,數據都是緩存在內存中。區別的是redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。
1、Redis安裝設置
Redis對於Linus是官方支持的,安裝和使用按照官方指導,Windows系統下安裝參照博文http://blog.csdn.net/renfufei/article/details/38474435/。
2、Redis與其他數據庫的對比
下圖展示了一部分在功能上與Redis有重疊的數據庫服務和緩存服務器,從這張表可以看到
名稱 |
類型 |
數據存儲選項 |
查詢類型 |
附加功能 |
---|---|---|---|---|
Redis |
使用內存存儲(in-memory)的非關系數據庫 |
字符串、列表、集合、散列表、有序集合 |
每種數據類型都有自己的專屬命令,另外還有批量操作(bulk operation)和不完全(partial)的事務支持 |
發布與訂閱,主從復制(master/slave replication),持久化,腳本(存儲過程,stored procedure) |
memcached |
使用內存存儲的鍵值緩存 |
鍵值之間的映射 |
創建命令、讀取命令、更新命令、刪除命令以及其他幾個命令 |
為提升性能而設的多線程服務器 |
MySQL |
關系數據庫 |
每個數據庫可以包含多個表,每個表可以包含多個行;可以處理多個表的視圖(view);支持空間(spatial)和第三方擴展 |
|
支持ACID性質(需要使用InnoDB),主從復制和主主復制 (master/master replication) |
PostgreSQL |
關系數據庫 |
每個數據庫可以包含多個表,每個表可以包含多個行;可以處理多個表的視圖;支持空間和第三方擴展;支持可定制類型 |
|
支持ACID性質,主從復制,由第三方支持的多主復制(multi-master replication) |
MongoDB |
使用硬盤存儲(on-disk)的非關系文檔存儲 |
每個數據庫可以包含多個表,每個表可以包含多個無schema(schema-less)的BSON文檔 |
創建命令、讀取命令、更新命令、刪除命令、條件查詢命令等 |
支持map-reduce操作,主從復制,分片,空間索引(spatial index) |
3、持久化方法
Redis擁有兩種不同的持久化方法,它們都可以用小而緊湊的格式將存儲在內存中的數據寫入硬盤。
第一種:時間點轉儲
轉儲操作既可以在“指定時間段內有指定數量的寫操作執行“這一條件被滿足時執行,又可以通過調用兩條轉儲到硬盤命令中的任何一台執行。
第二種:將所有修改了數據庫的命令都寫入一個只追加文件里面,用戶可以根據數據的重要程度,將只追加寫入設置為不同步,每秒同步一次或者每寫入一個命令就同步一次。
二、Redis數據結構
Redis可以存儲鍵與5種不同數據結構類型之間的映射,下面的表格介紹了它們的語義:
結構類型 |
結構存儲的值 |
結構的讀寫能力 |
---|---|---|
|
可以是字符串、整數或者浮點數 |
對整個字符串或者字符串的其中一部分執行操作;對整數和浮點數執行自增(increment)或者自減(decrement)操作 |
|
一個鏈表,鏈表上的每個節點都包含了一個字符串 |
從鏈表的兩端推入或者彈出元素;根據偏移量對鏈表進行修剪(trim);讀取單個或者多個元素;根據值查找或者移除元素 |
|
包含字符串的無序收集器(unordered collection),並且被包含的每個字符串都是獨一無二、各不相同的 |
添加、獲取、移除單個元素;檢查一個元素是否存在於集合中;計算交集、並集、差集;從集合里面隨機獲取元素 |
|
包含鍵值對的無序散列表 |
添加、獲取、移除單個鍵值對;獲取所有鍵值對 |
|
字符串成員(member)與浮點數分值(score)之間的有序映射,元素的排列順序由分值的大小決定 |
添加、獲取、刪除單個元素;根據分值范圍(range)或者成員來獲取元素 |
1、String字符串
Redis的String和其他編程語言或者其它鍵值存儲提供的字符串非常相似。下圖描述了字符串常用的三個命令:
命令 |
行為 |
---|---|
|
獲取存儲在給定鍵中的值 |
|
設置存儲在給定鍵中的值 |
|
刪除存儲在給定鍵中的值(這個命令可以用於所有類型) |
使用示例:
2、List列表
一個列表結構可以有序的存儲多個字符串。list常用的命令如下表所示:、
命令 |
行為 |
---|---|
|
將給定值推入列表的右端 |
|
獲取列表在給定范圍上的所有值 |
|
獲取列表在給定位置上的單個元素 |
|
從列表的左端彈出一個值,並返回被彈出的值 |
使用示例:
此外,redis列表還有從列表里面移除元素、將元素插入列表中間、將列表修剪至指定長度的命令,在此不再贅述。
3、set集合
Redis的集合和列表都可以存儲多個字符串,它們的不同之處在於,列表可以存儲多個相同的字符串,而集合則通過使用散列表來保證自己存儲的每個字符串都是各不相同的。set常用的命令如下表所示:
命令 |
行為 |
---|---|
|
將給定元素添加到集合 |
|
返回集合包含的所有元素 |
|
檢查給定元素是否存在於集合中 |
|
如果給定的元素存在於集合中,那么移除這個元素 |
使用示例:
4、Hash散列
Redis的散列可以存儲多個鍵值對之間的映射,和字符串一樣,散列存儲的值既可以是字符串又可以是數字值,並且可以對散列存儲的數字值執行自增和自減操作。散列常用的命令如下表所示:
命令 |
行為 |
---|---|
|
在散列里面關聯起給定的鍵值對 |
|
獲取指定散列鍵的值 |
|
獲取散列包含的所有鍵值對 |
|
如果給定鍵存在於散列里面,那么移除這個鍵 |
使用示例:
5、zset有序集合
有序集合和散列一樣,都用於存儲鍵值對:有序集合的鍵被稱為成員,每個成員都是獨一無二的,而有序集合的則被稱為分值,分值必須為浮點數。有序集合是Redis里面唯一一個既可以根據成員訪問元素(這一點和散列一樣),又可以根據分值以及分值的排列順序來訪問元素的結構。有序集合的常用命令如下表所示:
命令 |
行為 |
---|---|
|
將一個帶有給定分值的成員添加到有序集合里面 |
|
根據元素在有序排列中所處的位置,從有序集合里面獲取多個元素 |
|
獲取有序集合在給定分值范圍內的所有元素 |
|
如果給定成員存在於有序集合,那么移除這個成員 |
使用示例:
三、Java中使用Jedis操作Redis
使用Java操作Redis需要添加jar包依賴:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.3</version> </dependency>
測試代碼:
import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; public class JedisUtilTest { private Jedis jedis; @Before public void setUp() throws Exception { jedis = new Jedis("127.0.0.1", 6379); } @Test public void testString() { jedis.set("name", "xujian"); jedis.set("age", "23"); String username = jedis.get("name"); String age = jedis.get("age"); System.out.println(username + ":" + age); jedis.del("name"); // 刪除key對應的記錄 System.out.println(jedis.get("name")); // 執行結果為null jedis.incr("age"); // 進行加1操作 System.out.println(jedis.get("age")); } @Test public void testMap() { Map<String, String> user = new HashMap<String, String>(); user.put("name", "minxr"); user.put("pwd", "password"); jedis.hmset("user", user); // 取出user中的name,執行結果:[minxr]-->注意結果是一個泛型的List // 第一個參數是存入redis中map對象的key,后面跟的是放入map中的對象的key,后面的key可以跟多個,是可變參數 List<String> rsmap = jedis.hmget("user", "name"); System.out.println(rsmap); // 刪除map中的某個鍵值 // jedis.hdel("user","pwd"); System.out.println(jedis.hmget("user", "pwd")); // 因為刪除了,所以返回的是null System.out.println(jedis.hlen("user")); // 返回key為user的鍵中存放的值的個數1 System.out.println(jedis.exists("user"));// 是否存在key為user的記錄 返回true System.out.println(jedis.hkeys("user"));// 返回map對象中的所有key [pwd, name] System.out.println(jedis.hvals("user"));// 返回map對象中的所有value [minxr, // password] Iterator<String> iter = jedis.hkeys("user").iterator(); while (iter.hasNext()) { String key = iter.next(); System.out.println(key + ":" + jedis.hmget("user", key)); } } @Test public void testList() { // 開始前,先移除所有的內容 jedis.del("java framework"); System.out.println(jedis.lrange("java framework", 0, -1)); // 先向key java framework中存放三條數據 // lpush表示將元素插入到list的頭部 // rpush表示將元素插入到list的尾部 jedis.lpush("java framework", "spring"); jedis.lpush("java framework", "struts"); jedis.lpush("java framework", "hibernate"); // 再取出所有數據jedis.lrange是按范圍取出, // 第一個是key,第二個是起始位置,第三個是結束位置,jedis.llen獲取長度 -1表示取得所有 System.out.println(jedis.lrange("java framework", 0, -1)); } @Test public void testSet() { // 添加 jedis.sadd("sname", "minxr"); jedis.sadd("sname", "jarorwar"); jedis.sadd("sname", "tony"); jedis.sadd("sanme", "noname"); // 移除noname jedis.srem("sname", "noname"); System.out.println(jedis.smembers("sname"));// 獲取所有加入的value System.out.println(jedis.sismember("sname", "minxr"));// 判斷 minxr是否為sname集合的元素 System.out.println(jedis.srandmember("sname")); //從集合中隨機返回一個元素 System.out.println(jedis.scard("sname"));// 返回集合的元素個數 } @Test public void testZset() { jedis.zadd("myzset", 878, "xujian"); jedis.zadd("myzset", 123, "xiewei"); jedis.zadd("myzset", 345, "luyang"); jedis.zadd("myzset", 678, "xxy"); System.out.println(jedis.zcard("myzset"));//元素個數 Set<String> zset=jedis.zrange("myzset", 0, -1); for (Object object : zset) { System.out.println(object.toString()); } } }