1. 程式人生 > 其它 >Redis安裝配置與Jedis訪問資料庫

Redis安裝配置與Jedis訪問資料庫

目錄

一、NOSQL概要

NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是SQL”,泛指非關係型的資料庫。NoSQL資料庫的四大分類

鍵值(Key-Value)儲存資料庫

這一類資料庫主要會使用到一個雜湊表,這個表中有一個特定的鍵和一個指標指向特定的資料。Key/value模型對於IT系統來說的優勢在於簡單、易部署。但是如果DBA只對部分值進行查詢或更新的時候,Key/value就顯得效率低下了。 舉例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.

列儲存資料庫。

這部分資料庫通常是用來應對分散式儲存的海量資料。鍵仍然存在,但是它們的特點是指向了多個列。這些列是由列家族來安排的。如:Cassandra, HBase, Riak.

文件型資料庫

文件型資料庫的靈感是來自於Lotus Notes辦公軟體的,而且它同第一種鍵值儲存相類似。該型別的資料模型是版本化的文件,半結構化的文件以特定的格式儲存,比如JSON。文件型資料庫可 以看作是鍵值資料庫的升級版,允許之間巢狀鍵值。而且文件型資料庫比鍵值資料庫的查詢效率更高。如:CouchDB, MongoDb. 國內也有文件型資料庫SequoiaDB,已經開源。

圖形(Graph)資料庫

圖形結構的資料庫同其他行列以及剛性結構的SQL資料庫不同,它是使用靈活的圖形模型,並且能夠擴充套件到多個伺服器上。NoSQL資料庫沒有標準的查詢語言(SQL),因此進行資料庫查詢需要制定資料模型。許多NoSQL資料庫都有REST式的資料介面或者查詢API。如:Neo4J, InfoGrid, Infinite Graph.

NoSQL資料庫在以下的這幾種情況下比較適用:1、資料模型比較簡單;2、需要靈活性更強的IT系統;3、對資料庫效能要求較高;4、不需要高度的資料一致性;5、對於給定key,比較容易映射覆雜值的環境。

二、Redis概要

Redis是一個開源的使用ANSI C語言編寫、遵守BSD協議、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。它通常被稱為資料結構伺服器,因為值(value)可以是 字串(String), 雜湊(Map), 列表(list), 集合(sets)和有序集合(sorted sets)等型別。

Redis支援主從同步。資料可以從主伺服器向任意數量的從伺服器上同步,從伺服器可以是關聯其他從伺服器的主伺服器。這使得Redis可執行單層樹複製。存檔可以有意無意的對資料進行寫操作。由於完全實現了釋出/訂閱機制,使得從資料庫在任何地方同步樹時,可訂閱一個頻道並接收主伺服器完整的訊息釋出記錄。同步對讀取操作的可擴充套件性和資料冗餘很有幫助。

2.1、相關網站

官網:redis.io

中文網:http://www.redis.net.cn/

github:https://github.com/MSOpenTech/redis

下載地址:https://github.com/MSOpenTech/redis/releases

三、安裝與配置Redis

3.1、下載最新版的Redis

開啟redis在github上的網站:https://github.com/MSOpenTech/redis/releases,選擇下載最新版的Redis,寫該文字時最新版本是3.2.1版。

這裡我們選擇下載手動安裝包Redis-x64-3.2.100.zip。如果是32位的可以下載原始碼後自己編譯出32位的版本,在https://github.com/dmajkic/redis/downloads可以下載到32的安裝檔案,不過版本有點舊了。

3.2、新增環境變數

將下載後的安裝包解壓到磁碟中,最好是沒有中文路徑,沒有特殊字元的目錄下,比如:d:\redis目錄下。為了更加方便的使用Redis,可以新增環境變數,在“系統環境變數”中的“Path”變數下新增redis路徑,如下所示:

確定後啟動cmd,執行redis-server測試。

3.3、啟動伺服器

在命令模式下執行:redis-server.exe redis.windows.conf,如果執行提示未找到conf檔案,則把引數中的配置檔案路徑加上,如:

啟動成功後會有一個字元介面,提示連線的埠號是:6379,請不要關閉該伺服器,等待客戶端連線;這裡也可以把redis作成windows服務,不過redis多數情況會在linux平臺使用。

3.4、啟動客戶端

再用cmd開啟一個命令容器,輸入命令:redis-cli -h 127.0.0.1 -p 6379,執行成功後如下所示:

-h用於指定伺服器位置,-p用於指定埠號;如果想改變該內容可以修改.conf檔案。

3.5、測試並執行

新增資料:set <key> <value> 

獲得資料:get <key>

是否存在:exists <key>

刪除資料:del <key>

修改資料:set <key> <value>

幫助命令:help <命令名稱>

查詢鍵:keys <名稱能配符>

設定過期時間:expire <key> <秒數>

刪除過期時間:persist <key> 

info
伺服器基本資訊

monitor

實時轉儲收到的請求

config get
獲取伺服器的引數配置

flushdb
清空當前資料庫

flushall
清除所有資料庫

 更多命令:http://doc.redisfans.com/

三、常用命令
    1)連線操作命令
    quit:關閉連線(connection)
    auth:簡單密碼認證
    help cmd: 檢視cmd幫助,例如:help quit
    
    2)持久化
    save:將資料同步儲存到磁碟
    bgsave:將資料非同步儲存到磁碟
    lastsave:返回上次成功將資料儲存到磁碟的Unix時戳
    shundown:將資料同步儲存到磁碟,然後關閉服務
    
    3)遠端服務控制
    info:提供伺服器的資訊和統計
    monitor:實時轉儲收到的請求
    slaveof:改變複製策略設定
    config:在執行時配置Redis伺服器
    
    4)對value操作的命令
    exists(key):確認一個key是否存在
    del(key):刪除一個key
    type(key):返回值的型別
    keys(pattern):返回滿足給定pattern的所有key
    randomkey:隨機返回key空間的一個
    keyrename(oldname, newname):重新命名key
    dbsize:返回當前資料庫中key的數目
    expire:設定一個key的活動時間(s)
    ttl:獲得一個key的活動時間
    select(index):按索引查詢
    move(key, dbindex):移動當前資料庫中的key到dbindex資料庫
    flushdb:刪除當前選擇資料庫中的所有key
    flushall:刪除所有資料庫中的所有key
    
    5)String
    set(key, value):給資料庫中名稱為key的string賦予值value
    get(key):返回資料庫中名稱為key的string的value
    getset(key, value):給名稱為key的string賦予上一次的value
    mget(key1, key2,…, key N):返回庫中多個string的value
    setnx(key, value):新增string,名稱為key,值為value
    setex(key, time, value):向庫中新增string,設定過期時間time
    mset(key N, value N):批量設定多個string的值
    msetnx(key N, value N):如果所有名稱為key i的string都不存在
    incr(key):名稱為key的string增1操作
    incrby(key, integer):名稱為key的string增加integer
    decr(key):名稱為key的string減1操作
    decrby(key, integer):名稱為key的string減少integer
    append(key, value):名稱為key的string的值附加value
    substr(key, start, end):返回名稱為key的string的value的子串
    
    6)List 
    rpush(key, value):在名稱為key的list尾新增一個值為value的元素
    lpush(key, value):在名稱為key的list頭新增一個值為value的 元素
    llen(key):返回名稱為key的list的長度
    lrange(key, start, end):返回名稱為key的list中start至end之間的元素
    ltrim(key, start, end):擷取名稱為key的list
    lindex(key, index):返回名稱為key的list中index位置的元素
    lset(key, index, value):給名稱為key的list中index位置的元素賦值
    lrem(key, count, value):刪除count個key的list中值為value的元素
    lpop(key):返回並刪除名稱為key的list中的首元素
    rpop(key):返回並刪除名稱為key的list中的尾元素
    blpop(key1, key2,… key N, timeout):lpop命令的block版本。
    brpop(key1, key2,… key N, timeout):rpop的block版本。
    rpoplpush(srckey, dstkey):返回並刪除名稱為srckey的list的尾元素,並將該元素新增到名稱為dstkey的list的頭部

    7)Set
    
sadd(key, member):向名稱為key的set中新增元素member
    srem(key, member) :刪除名稱為key的set中的元素member
    spop(key) :隨機返回並刪除名稱為key的set中一個元素
    smove(srckey, dstkey, member) :移到集合元素
    scard(key) :返回名稱為key的set的基數
    sismember(key, member) :member是否是名稱為key的set的元素
    sinter(key1, key2,…key N) :求交集
    sinterstore(dstkey, (keys)) :求交集並將交集儲存到dstkey的集合
    sunion(key1, (keys)) :求並集
    sunionstore(dstkey, (keys)) :求並集並將並集儲存到dstkey的集合
    sdiff(key1, (keys)) :求差集
    sdiffstore(dstkey, (keys)) :求差集並將差集儲存到dstkey的集合
    smembers(key) :返回名稱為key的set的所有元素
    srandmember(key) :隨機返回名稱為key的set的一個元素
    
    
8)Hash
    hset(key, field, value):向名稱為key的hash中新增元素field
    hget(key, field):返回名稱為key的hash中field對應的value
    hmget(key, (fields)):返回名稱為key的hash中field i對應的value
    hmset(key, (fields)):向名稱為key的hash中新增元素field 
    hincrby(key, field, integer):將名稱為key的hash中field的value增加integer
    hexists(key, field):名稱為key的hash中是否存在鍵為field的域
    hdel(key, field):刪除名稱為key的hash中鍵為field的域
    hlen(key):返回名稱為key的hash中元素個數
    hkeys(key):返回名稱為key的hash中所有鍵
    hvals(key):返回名稱為key的hash中所有鍵對應的value
    hgetall(key):返回名稱為key的hash中所有的鍵(field)及其對應的value

3.6、新增windows服務

如果不新增windows服務,redis-server.exe程式一直要以GUI的形式開啟在工作列,有時候不小心會被關閉,其實也可以像其它資料庫如Oracle一樣將redis做成一個服務,以服務的形式執行,註冊服務的方法如下:

3.6.1、在命令模式下切換到redis安裝目錄 3.6.2、執行指令如下命令: redis-server --service-install redis.windows.conf --loglevel verbose  --service-name Redis
解釋: --service-install redis.windows.conf 指定redis配置檔案 --loglevel verbose  指定日誌級別 --service-name Redis 指定服務名稱 執行命令後的結果:

在windows服務列表中就可以看到redis服務了,可以將自動啟動修改為手動啟動:

如果電腦上安裝了很多的服務,每次開啟服務介面啟動不是很方便,可以使用一個批處理完成。批處理指令碼ServiceManager.bat如下:

@echo off
:a
echo 請選擇要執行批處理命令:
echo ------------------------------------------------------
echo     1    開啟MSSQLServer
echo     2    關閉MSSQLServer
echo     3    開啟Oracle
echo     4    關閉Oracle
echo     5    快速關機
echo     6    開啟MySQL
echo     7    關閉MySQL
echo     8    開啟Redis
echo     9    關閉Redis
echo ------------------------------------------------------
Set/p var1=請輸入您要執行的指令:[1/2/3/4/5]
if %var1% ==1 goto C1
if %var1% ==2 goto C2
if %var1% ==3 goto C3
if %var1% ==4 goto C4
if %var1% ==5 goto C5
if %var1% ==6 goto C6
if %var1% ==7 goto C7
if %var1% ==8 goto C8
if %var1% ==9 goto C9
echo.
cls
goto a:
echo.
:C1
net Start MSSQLServer /Y
goto EndApp
echo.
:C2
net Stop MSSQLServer /Y
goto EndApp
echo.
:C3
net Start OracleServiceORCL /Y
net Start OracleOraDb11g_home1TNSListener /Y
goto EndApp
echo.
:C4
net stop OracleServiceORCL /Y
net stop OracleOraDb11g_home1TNSListener /Y
goto EndApp
echo.
:C5
shutdown -s -f -t 0
goto EndApp
echo.
:C6
net Start MySQL /Y
goto EndApp
echo.
:C7
net Stop MySQL /Y
goto EndApp
echo.
:C8
net Start redis /Y
goto EndApp
echo.
:C9
net Stop redis /Y
goto EndApp
echo.
:EndApp
Set/p var3=是否繼續操作:[y/n]
If %var3% == y goto a:

執行效果:

上面這部分可省略。

四、使用Jedis訪問Redis資料庫

Jedis是redis的java版的客戶端實現,在java程式中我們可以通過Jedis訪問Redis資料庫,原始碼地址(https://github.com/xetorthio/jedis),實現訪問的方法如下:

4.1、引用或依賴Jedis包

4.1.1、如果使用Maven,修改pom.xml檔案,新增Jedis的依賴,修改後的pom.xml檔案如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zhangguo</groupId>
    <artifactId>JedisDemo</artifactId>
    <version>0.0.1</version>

    <dependencies>
        <!-- Jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.1</version>
        </dependency>
    </dependencies>

</project>

 引用成功後的結果:

從引用的結果可以發現jedis使用了commons的連線池技術。

4.1.2、如果直接新增引用,可以去github下載jedis原始碼包自行編譯,下載地址是:https://github.com/xetorthio/jedis/releases,當前最新版本2.8.1。

如果想直接下載jar包,可以到Maven共享資源庫(http://search.maven.org/)下載,如下所示:

4.2、呼叫Jedis

先開啟redis資料庫服務,處理監聽狀態,在java專案中編寫如下測試程式碼:

package com.zhangguo.jedisdemo;

import redis.clients.jedis.Jedis;

public class HelloJedis {
    public static void main(String[] args) {
        //例項化一個jedis物件,連線到指定的伺服器,指定連線埠號
        Jedis jedis = new Jedis("127.0.0.1",6379);
        //將key為message的資訊寫入redis資料庫中
        jedis.set("message", "Hello Redis!");
        //從資料庫中取出key為message的資料
        String value = jedis.get("message");
        System.out.println(value);
        //關閉連線
        jedis.close();
    }
}

執行結果:

五、Redis提供的持久化機制

Redis是一種高效能的資料庫,可以選擇持久化,也可以選擇不持久化。如果要儲存,就會存在資料同步的問題,可以簡單認為一份資料放在記憶體中(快照),一份資料放在磁碟上,Redis提供了很靈活的持久化辦法:

5.1、RDB持久化

該機制是指在指定的時間間隔內將記憶體中的資料集快照寫入磁碟。 比如每隔15分鐘有資料變化將記憶體中的資料與磁碟同步。

redis預設配置中就採用了該方法,如下所示:

# after 900 sec (15 min) if at least 1 key changed

15分種內如果有1個以上的內容發生了變化就執行儲存
# after 300 sec (5 min) if at least 10 keys changed

5分種內如果有10個以上的內容發生了變化就執行儲存
# after 60 sec if at least 10000 keys changed

1分種內如果有10000 個以上的內容發生了變化就執行儲存

2). AOF持久化:
該機制將以日誌的形式記錄伺服器所處理的每一個寫操作,在Redis伺服器啟動之初會讀取該檔案來重新構建資料庫,以保證啟動後資料庫中的資料是完整的。
3). 無持久化:
我們可以通過配置的方式禁用Redis伺服器的持久化功能,這樣我們就可以將Redis視為一個功能加強版的memcached了。
4). 同時應用AOF和RDB。

5.2、RDB機制的優勢和劣勢:

RDB存在哪些優勢呢?
1). 一旦採用該方式,那麼你的整個Redis資料庫將只包含一個檔案,這對於檔案備份而言是非常完美的。比如,你可能打算每個小時歸檔一次最近24小時的資料,同時還要每天歸檔一次最近30天的資料。通過這樣的備份策略,一旦系統出現災難性故障,我們可以非常容易的進行恢復。
2). 對於災難恢復而言,RDB是非常不錯的選擇。因為我們可以非常輕鬆的將一個單獨的檔案壓縮後再轉移到其它儲存介質上。
3). 效能最大化。對於Redis的服務程序而言,在開始持久化時,它唯一需要做的只是fork出子程序,之後再由子程序完成這些持久化的工作,這樣就可以極大的避免服務程序執行IO操作了。
4). 相比於AOF機制,如果資料集很大,RDB的啟動效率會更高。

RDB又存在哪些劣勢呢?
1). 如果你想保證資料的高可用性,即最大限度的避免資料丟失,那麼RDB將不是一個很好的選擇。因為系統一旦在定時持久化之前出現宕機現象,此前沒有來得及寫入磁碟的資料都將丟失。
2). 由於RDB是通過fork子程序來協助完成資料持久化工作的,因此,如果當資料集較大時,可能會導致整個伺服器停止服務幾百毫秒,甚至是1秒鐘。

5.3、AOF機制的優勢和劣勢:

AOF的優勢有哪些呢?
1). 該機制可以帶來更高的資料安全性,即資料永續性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事實上,每秒同步也是非同步完成的,其效率也是非常高的,所差的是一旦系統出現宕機現象,那麼這一秒鐘之內修改的資料將會丟失。而每修改同步,我們可以將其視為同步持久化,即每次發生的資料變化都會被立即記錄到磁碟中。可以預見,這種方式在效率上是最低的。至於無同步,無需多言,我想大家都能正確的理解它。
2). 由於該機制對日誌檔案的寫入操作採用的是append模式,因此在寫入過程中即使出現宕機現象,也不會破壞日誌檔案中已經存在的內容。然而如果我們本次操作只是寫入了一半資料就出現了系統崩潰問題,不用擔心,在Redis下一次啟動之前,我們可以通過redis-check-aof工具來幫助我們解決資料一致性的問題。
3). 如果日誌過大,Redis可以自動啟用rewrite機制。即Redis以append模式不斷的將修改資料寫入到老的磁碟檔案中,同時Redis還會建立一個新的檔案用於記錄此期間有哪些修改命令被執行。因此在進行rewrite切換時可以更好的保證資料安全性。
4). AOF包含一個格式清晰、易於理解的日誌檔案用於記錄所有的修改操作。事實上,我們也可以通過該檔案完成資料的重建。

AOF的劣勢有哪些呢?
1). 對於相同數量的資料集而言,AOF檔案通常要大於RDB檔案。
2). 根據同步策略的不同,AOF在執行效率上往往會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效。

5.4、其它

5.4.1. Snapshotting:
預設情況下,Redis會將資料集的快照dump到dump.rdb檔案中。此外,我們也可以通過配置檔案來修改Redis伺服器dump快照的頻率,在開啟6379.conf檔案之後,我們搜尋save,可以看到下面的配置資訊:
save 900 1 #在900秒(15分鐘)之後,如果至少有1個key發生變化,則dump記憶體快照。
save 300 10 #在300秒(5分鐘)之後,如果至少有10個key發生變化,則dump記憶體快照。
save 60 10000 #在60秒(1分鐘)之後,如果至少有10000個key發生變化,則dump記憶體快照。

5.4.2. Dump快照的機制:
1). Redis先fork子程序。
2). 子程序將快照資料寫入到臨時RDB檔案中。
3). 當子程序完成資料寫入操作後,再用臨時檔案替換老的檔案。

5.4.3. AOF檔案:
上面已經多次講過,RDB的快照定時dump機制無法保證很好的資料永續性。如果我們的應用確實非常關注此點,我們可以考慮使用Redis中的AOF機制。對於Redis伺服器而言,其預設的機制是RDB,如果需要使用AOF,則需要修改配置檔案中的以下條目:
將appendonly no改為appendonly yes
從現在起,Redis在每一次接收到資料修改的命令之後,都會將其追加到AOF檔案中。在Redis下一次重新啟動時,需要載入AOF檔案中的資訊來構建最新的資料到記憶體中。

5.4.5. AOF的配置:
在Redis的配置檔案中存在三種同步方式,它們分別是:
appendfsync always #每次有資料修改發生時都會寫入AOF檔案。
appendfsync everysec #每秒鐘同步一次,該策略為AOF的預設策略。
appendfsync no #從不同步。高效但是資料不會被持久化。

5.4.6. 如何修復壞損的AOF檔案:
1). 將現有已經壞損的AOF檔案額外拷貝出來一份。
2). 執行"redis-check-aof --fix <filename>"命令來修復壞損的AOF檔案。
3). 用修復後的AOF檔案重新啟動Redis伺服器。

5.4.7. Redis的資料備份:
在Redis中我們可以通過copy的方式線上備份正在執行的Redis資料檔案。這是因為RDB檔案一旦被生成之後就不會再被修改。Redis每次都是將最新的資料dump到一個臨時檔案中,之後在利用rename函式原子性的將臨時檔案改名為原有的資料檔名。因此我們可以說,在任意時刻copy資料檔案都是安全的和一致的。鑑於此,我們就可以通過建立cron job的方式定時備份Redis的資料檔案,並將備份檔案copy到安全的磁碟介質中。

5.5、立即寫入

//立即儲存,同步儲存
    public static void syncSave() throws Exception{
        Jedis jedis=new Jedis("127.0.0.1",6379);
        for (int i = 0; i <1000; i++) {
            jedis.set("key"+i, "Hello"+i);
            System.out.println("設定key"+i+"的資料到redis");
            Thread.sleep(2);
        }
        //執行儲存,會在伺服器下生成一個dump.rdb資料庫檔案
        jedis.save();
        jedis.close();
        System.out.println("寫入完成");
    }

執行結果:

這裡的save方法是同步的,沒有寫入完成前不執行後面的程式碼。

5.6、非同步寫入

    //非同步儲存
    public static void asyncSave() throws Exception{
        Jedis jedis=new Jedis("127.0.0.1",6379);
        for (int i = 0; i <1000; i++) {
            jedis.set("key"+i, "Hello"+i);
            System.out.println("設定key"+i+"的資料到redis");
            Thread.sleep(2);
        }
        //執行非同步儲存,會在伺服器下生成一個dump.rdb資料庫檔案
        jedis.bgsave();
        jedis.close();
        System.out.println("寫入完成");
    }

如果資料量非常大,要儲存的內容很多,建議使用bgsave,如果內容少則可以使用save方法。關於各方式的比較源自網友的部落格。

六、綜合示例

通過一個簡單的汽車管理示例實現使用redis資料庫完成增刪改查功能。

6.1、定義一個名為Car的Bean

package com.zhangguo.entities;

import java.io.Serializable;

/*
 * 汽車類
 */
public class Car implements Serializable {
    private static final long serialVersionUID = 1L;
    /*
     * 編號
     */
    private int id;
    /*
     * 車名
     */
    private String name;
    /*
     * 車速 
     */
    private double speed;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getSpeed() {
        return speed;
    }
    public void setSpeed(double speed) {
        this.speed = speed;
    }
    public Car(int id, String name, double speed) {
        this.id = id;
        this.name = name;
        this.speed = speed;
    }
    public Car() {
    }
    @Override
    public String toString() {
        return "Car [id=" + id + ", name=" + name + ", speed=" + speed + "]";
    }
}

6.2、定義一個工具類,實現將序列化與反序列化功能

package com.zhangguo.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializeUitl {
    /**
     * 序列化
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 反序列化
     */
    public static <T> T deSerialize(byte[] bytes,Class<T> clazz) {
        ByteArrayInputStream bais = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (T)ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

6.3、定義一個CarDAO的資料訪問類

package com.zhangguo.dao;

import java.util.ArrayList;
import java.util.List;
import com.zhangguo.entities.Car;
import com.zhangguo.utils.SerializeUitl;

import redis.clients.jedis.Jedis;

/*
 * 資料訪問類
 */
public class CarDAO {

    //汽車集合
    private List<Car> cars;

    //初始化時載入所有的資料
    public CarDAO() {
        load();
    }

    /*
     * 將資料儲存到redis資料庫中
     */
    public void save() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.set("cars".getBytes(), SerializeUitl.serialize(cars));
        jedis.bgsave();
        jedis.close();
    }

    /*
     * 從redis資料庫中載入資料
     */
    public void load() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        byte[] byties = jedis.get("cars".getBytes());
        if (byties != null && byties.length > 0) {
            cars = SerializeUitl.deSerialize(byties, Car.class);
        }else{
            cars=new ArrayList<Car>();
        }
        jedis.close();
    }
    
    //新增
    public void add(Car car){
        this.cars.add(car);
        save();
    }
    
    //獲得物件通過編號
    public Car getCarById(int id){
        for (Car car : cars) {
            if(car.getId()==id){
                return car;
            }
        }
        return null;
    }
    
    //移除
    public void remove(int id){
        cars.remove(getCarById(id));
        save();
    }

    //獲得所有
    public List<Car> getCars() {
        return cars;
    }

    //批量新增
    public void setCars(List<Car> cars) {
        this.cars = cars;
        save();
    }
}

6.4、測試執行

package com.zhangguo.test;

import java.util.ArrayList;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import com.zhangguo.dao.CarDAO;
import com.zhangguo.entities.Car;

public class CarTest {

    static CarDAO cardao;
    
    @BeforeClass
    public static void before(){
        cardao=new CarDAO();
    }
    
    /*
     * 批量新增
     */
    @Test
    public void testSetCars() {
        List<Car> cars=new ArrayList<Car>();
        cars.add(new Car(1001, "Benz 600", 230));
        cars.add(new Car(1002, "BMW X7+", 200));
        cars.add(new Car(1003, "Audi A8", 180));
        cardao.setCars(cars);
    }
    
    /*
     * 查詢所有
     */
    @Test
    public void testGetCars() {
        for (Car car : cardao.getCars()) {
            System.out.println(car);
        }
    }
    
    /*
     * 增加一輛車
     */
    @Test
    public void testAdd() {
        cardao.add(new Car(1004,"BYD F8",150));
    }

    /*
     * 根據編號獲得一輛車
     */
    @Test
    public void testGetCarById() {
        System.out.println("----------獲得編號為1001的車----------");
        System.out.println(cardao.getCarById(1001));
    }

    /*
     * 移除汽車
     */
    @Test
    public void testRemove() {
        System.out.println("----------移除編號為1004的車----------");
        cardao.remove(1004);
    }

}

執行結果

6.5、小結

這僅僅是一個示例,在功能與效能方面都有很大的改進空間,拋磚引玉罷了。