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、小結

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

七、示例下載

 點擊下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM