JAVA WEB DAY 17_ Redis
文章目錄
- Redis
- 01_NOSQL的概述-[★★]
- 02_為什麼要使用NOSQL-[★★]
- 03_Redis的安裝和啟動-[★★]
- 04_Redis五種資料型別及結構概述-[★★★★★]
- 05_string型別操作命令-[★★★★★]
- 06_hash型別操作命令-[★★★]
- 07_list型別操作命令-[★★★]
- 08_set型別操作命令-[★★★]
- 09_zset型別操作命令-[★★]
- 10_客戶端工具使用和redis通用命令-[★★★★★]
- 11_Redis的持久化-RDB持久化機制-[★★]
- ## 12_Redis的持久化-AOF持久化機制-[★★]
- 13_AOF重寫機制介紹-[★]
- 14_AOF和RDB常見問題-[★★]
- 15_Jedis的基本使用-[★★★★★]
- 16_Jedis連線池建立和使用-[★★★★★]
- 17_Jedis連線池工具類實現-[★★★★★]
- 18_案例-非同步載入聯絡人-分析和環境準備-[★★★★★]
- 19_案例-非同步載入聯絡人-伺服器端實現-[★★★★★]
- 20_案例-非同步載入聯絡人-前端頁面實現-[★★★★★]
Redis
01_NOSQL的概述-[★★]
NOSQL:泛指非關係型資料庫
02_為什麼要使用NOSQL-[★★]
NOSQL的好處:快
1. 解決高併發資料訪問問題
2. 解決高海亮資料儲存問題
具體表現為對如下問題的解決:
High Performance - 資料庫高併發訪問
在同一個時間點,同時有海量的使用者併發訪問。往往要達到每秒上萬次讀寫請求。關聯式資料庫應付上萬次SQL查詢還勉強頂得住,但是應付上萬次SQL寫資料請求,硬碟IO就已經無法承受了。
- 如天貓的雙11,從凌晨0點到2點這段時間,每秒達到上千萬次的訪問量。
- 12306春運期間,過年回家買火車搶票的時間,使用者不斷查詢有沒有剩餘票。
Huge Storage - 高海量資料的儲存
資料庫中資料量特別大,資料庫表中每天產生海量的資料。
類似QQ,微信,微博,每天使用者產生海量的使用者動態,每天產生幾千萬條記錄。對於關聯式資料庫來說,在一張幾億條記錄的表裡面進行SQL查詢,效率是極其低下乃至不可忍受的。
03_Redis的安裝和啟動-[★★]
- redis儲存資料的格式:鍵值對形式儲存
- 啟動redis客戶端的可執行程式是:redis-cli.exe
- 啟動redis伺服器的可執行程式是:redis-server.exe
- redis伺服器使用的埠號是:6379
- Redis 安裝步驟:
解壓即完成安裝
注意事項
- 安裝目錄不要包含中文
- 目錄不要太深
- 硬碟需要至少有20G記憶體空間
- Redis 目錄結構
目錄或檔案 | 作用 |
---|---|
redis-benchmark.exe | 用於 Reids 的效能測試工具 |
redis-check-aof.exe | AOF 日誌檔案修復工具 |
redis-check-dump.exe | RDB 檔案修改工具 |
redis-cli.exe | client 命令列的客戶端工具 |
redis-server.exe | server 伺服器端的啟動程式 |
redis.windows.conf | redis 在 window 下的配置檔案 |
- Redis啟動和停止步驟
- 啟動redis
進入redis解壓目錄:雙擊redis-server.exe檔案- 停止redis
關閉伺服器視窗即可停止
04_Redis五種資料型別及結構概述-[★★★★★]
- redis五種資料型別分別是:
string
hash
list
set
zset- 實際開發中主要使用哪種資料型別:string
關於key的定義,注意如下幾點:
- 不建議key名字太長,通常不超過1024,如果太長會影響查詢的速度。
- 不建議太短,太短會降低可讀性。
- 一般在公司,都有統一命名規範
05_string型別操作命令-[★★★★★]
- 往redis儲存鍵值對字串的命令是:set 鍵 值
- 從redis中根據鍵獲得值的命令是:get 鍵
- 從redis中根據鍵刪除鍵值對的命令是:del 鍵
- 命令語法
命令 | 說明 |
---|---|
set 鍵 值 | 新增或修改鍵值對 |
get 鍵 | 根據鍵獲得值 |
del 鍵 | 根據鍵刪除鍵值對 |
- 命令演示
- 新增一個鍵為company,值為qingruan
- 再設定一個鍵為company,值為baidun
- 得到company的元素
- 刪除company元素
- 再次刪除company看返回值是否相同
- 得到company看返回值是多少
- 執行效果
06_hash型別操作命令-[★★★]
hash型別底層結構對應java的哪種型別?HashMap
- 命令語法
命令 | 說明 |
---|---|
hset 鍵 欄位 值 | 向指定的中新增一對hash型別的欄位名和值 |
hget 鍵 欄位 | 取出指定鍵的指定欄位的值 |
hmset 鍵 欄位 值 欄位 值 | mulitple,一次向某個鍵中設定多個欄位名和值 |
hmget 鍵 欄位 欄位 | 一次從指定的鍵中得到多個欄位的值 |
hdel 鍵 欄位 欄位 | 刪除一個鍵中的一個或多個欄位 |
hgetall 鍵 | 得到某個鍵所有的欄位值 |
- 命令演示
- 建立hash型別的鍵為user,並且新增一個欄位為username,值為pkxing
- 向user中新增欄位為password,值為12345
- 向user中新增欄位為age,值為18
- 分別得到user中的username、password和age的欄位值
- 向user中同時新增多個欄位和值,birthday 2018-01-01 sex male
- 同時取得多個欄位:age 和 sex
- 得到user中所有的欄位和值
- 刪除user中的生日和密碼欄位
- 執行效果
07_list型別操作命令-[★★★]
1.list資料型別的特點:有序可重複
2.list型別底層結構對應java的哪種型別:ArrayList
- 命令語法
命令 | 行為 |
---|---|
lpush 鍵 元素 元素 | left push在列表的左邊向指定的鍵中新增列表元素,如果該鍵並不存在,Redis將為該鍵建立一個新的連結串列,如果這個鍵已經存在,則是向list新增元素。 |
rpush 鍵 元素 元素 | right push在列表的右邊向指定的鍵中新增列表元素 |
lpop 鍵 | left pop從指定鍵中的左邊彈出一個元素,列表中的元素就刪除了。 |
rpop 鍵 | right pop從指定鍵的右邊彈出一個元素,列表中的元素就刪除了。 |
lrange 鍵 開始 結束 | 從指定鍵的列表中取出指定範圍的元素列表,從左邊數起從0開始,從右邊數起從-1開始。如果要取整個列表,開始是0,結束是-1 |
llen 鍵 | 得到指定列表的長度 |
- 命令演示
- 向mylist鍵的列表中,從左邊新增a b c三個元素
- 從右邊新增one two three三個元素
- 查詢所有的元素
- 從右邊新增一個重複的元素three
- 刪除最右邊的元素three
- 刪除最左邊的元素c
- 獲取列表中元素的個數
- 執行效果
08_set型別操作命令-[★★★]
- set資料型別的特點:無序且不可重複
- list型別底層結構對應java的哪種型別:HashSet
- 命令語法
命令 | 行為 |
---|---|
sadd 鍵 元素 元素 | 向set集合中新增1個或多個元素 |
smembers 鍵 | 查詢指定的集合中所有的元素 |
sismember 鍵 元素 | 判斷指定的元素是否在某個集合中,如果存在返回1,否則返回0 |
srem 鍵 元素 元素 | remove刪除指定的一個或多個元素 |
- 命令演示
- 向myset集合中新增A B C 1 2 3 六個元素
- 再向myset中新增B元素,看能否新增成功
- 顯示所有的成員,發現與新增的元素順序不同,元素是無序的
- 刪除其中的C這個元素,再檢視結果
- 判斷A是否在myset集合中
- 判斷D是否在myset集合中
- 執行效果
09_zset型別操作命令-[★★]
- 命令語法
命令 | 描述 |
---|---|
zadd 鍵 分數 值 分數 值 | 新增1個或多個元素,每個元素都有一個分數 |
zrange 鍵 開始索引 結束索引 | 獲取指定範圍的元素,得到所有的元素,索引是0到-1 |
zrem 鍵 值 值 | 刪除一個或多個值 |
zcard 鍵 | 得到元素個數 |
zrank 鍵 值 | 得到元素的索引號 |
zscore 鍵 值 | 得到元素的分數 |
- 命令演示
- 新增鍵country,分數是10,值是Japan
- 新增鍵country,分數是5,值是USA,新增鍵country,分數是50,值是Russian
- 新增鍵country,分數是1,值是China,分數是120,值是Korea
- 查詢country中所有的元素
- 查詢Japan的索引號(從0開始)
- 刪除值為USA的元素
- 查詢country中還有多少個元素
- 顯示Russian的分數值
10_客戶端工具使用和redis通用命令-[★★★★★]
- 通用命令語法
命令 | 功能 |
---|---|
keys 匹配字元 | 查詢當前資料庫中由哪些鍵 * 匹配多個字元 ? 匹配1個字元 |
del 鍵 1 鍵 2 | 可以刪除任意鍵,可以一次刪除多個鍵 |
exits 鍵 | 是否存在指定的鍵 |
type 鍵 | 判斷指定的鍵它的值是什麼型別,如:string,hash,list,set,none |
select 資料庫編號 | 選擇指定的資料庫,0~15 |
move 鍵 資料庫編號 | 將某個鍵移動到另一個資料庫中,如果另一個資料庫中有同名的鍵,則移動失敗。 |
- 命令演示
- 新增字串name的值為zhangsan
- 顯示所有的鍵
- 顯示所有以my開頭的鍵
- 顯示所有my後面有三個字元的鍵
- 新增一個字串:name2 lisi
- 新增一個list:name3 a b c d
- 顯示所有的鍵
- 一次刪除name2和name3這兩個鍵,其中name2和name3是不同的型別,顯示所有鍵
- 分別判斷name和name2是否存在
- 分別判斷name user myset mylist分別是什麼型別
- 切換資料庫到15,向15中新增一個name2 wangwu,得到name2的值顯示。
- 將15中的name2移到0中
- 切換到資料庫0,顯示所有的鍵
- 執行結果
11_Redis的持久化-RDB持久化機制-[★★]
問:把客戶端和服務端都關閉了,再重新開啟伺服器和客戶端,資料會不會丟失?
答:可能會部分丟失,可能會全部丟失
- RDB持久化機制的配置
在redis.windows.conf配置檔案中的SNAPSHOTTING快照中有如下說明:
語法 | 說明 |
---|---|
save<時間間隔><修改鍵數> | 在指定的時間間隔內,修改了多少個鍵,則進行持久化的操作 |
如下面配置的是RDB方式資料持久化時機,必須兩個條件都要滿足
關鍵字 | 時間(秒) | 修改鍵數 | 解釋 |
---|---|---|---|
save | 900 | 1 | 在15分鐘內如果修改了1個鍵,則進行持久化操作 |
save | 600 | 10 | 在5分鐘內如果修改了10個鍵,則進行持久化操作 |
save | 60 | 10000 | 在1分鐘內如果修改了1萬個鍵,則進行持久化操作 |
- RDB持久化記憶體的資料到dump.rdb檔案,檔案中會儲存鍵值對資料。
- RDB持久化的時候是將當時記憶體中所有的鍵值對一次性的持久化到dump.rdb。
示例演示-RDB持久化資料
-
需求:修改rdb持久化策略方案,設定20秒內修改3個鍵進行持久化資料到dump.rdb檔案中。
-
實現步驟:
- 修改配置檔案:redis.windows.conf 的101行,增加如下配置
save 20 3
- 重啟redis伺服器端:要求啟動的時候指明配置檔案啟動
3. 開啟DOS命令列視窗,切換到redis安裝目錄:cd d:/redis 4. 啟動伺服器指定配置檔案啟動,格式:redis-server.exe redis.windows.conf
- 啟動客戶端,測試在20秒內寫入3個鍵
- 關閉伺服器,再次啟動看是否有持久化
- RDB執行持久化的機制:在指定時間段內修改了指定數量的鍵時才執行持久化操作。
- RDB持久化機制的優點
- 因為不是實時持久化,所以效率高。
- 持久化檔案中只記錄記憶體中鍵值對的結果,不會記錄對鍵值對修改的過程。
- RDB持久化機制的缺點
- 因為不是實時持久化,所以資料容易丟失。
- 當一次持久化資料很大的時候,會導致伺服器暫停。
## 12_Redis的持久化-AOF持久化機制-[★★]
- AOF持久化機制的配置
開啟AOF持久化
AOF預設是關閉的,首先需要開啟AOF模式.
引數配置 | 說明 |
---|---|
appendonly no/yes | yes表示開啟持久化,no表示關閉,預設是關閉 如果開啟會在硬碟上生成一個檔案appendonly.aof |
AOF 持久化時機
關鍵字 | 持久化時機 | 解釋 |
---|---|---|
appendfsync | always | 每次修改都持久化,效率最低 |
appendfsync | everysec | 每秒持久化一次 |
appendfsync | noi | 不持久化,效率最高 |
示例演示-AOF持久化資料
-
需求:開啟AOF機制進行持久化資料測試。
-
實現步驟:
- 開啟AOF機制:修改配置檔案:redis.windows.conf,將393行修改如下
appendonly yes
- 重啟redis伺服器端:啟動的時候指明配置檔案啟動
3. 開啟DOS命令列視窗,切換到redis安裝目錄:cd d:/redis 4. 啟動伺服器指定配置檔案啟動,格式:redis-server.exe redis.windows.conf * 此時在伺服器目錄下出現appendonly.aof檔案。大小是0個位元組。
- 啟動客戶端,新增3個鍵
- 開啟appendonly.aof檔案,檢視檔案的變化,會發現檔案記錄了所有操作的過程。
- 關閉伺服器,再次啟動看是否有持久化
- AOF執行持久化的機制:每秒執行一次持久化操作。
- AOF持久化機制的優點:
- 因為持久化的頻率更高了,所以資料更加安全,更不容易丟失。
- AOF持久化機制的缺點:
- 因為持久化的頻率更高了,導致效能低了。
- 因為日誌檔案中記錄的所有修改的操作,在執行恢復資料過程中效率低。
13_AOF重寫機制介紹-[★]
為什麼需要AOF重寫
為了解決AOF檔案體積膨脹的問題,Redis提供了AOF重寫功能:Redis伺服器可以建立一個新的AOF檔案來替代現有的AOF檔案,新舊兩個檔案所儲存的資料庫狀態是相同的,但是新的AOF檔案不會包含任何浪費空間的冗餘命令,通常體積會較舊AOF檔案小很多。
set name jack
set name rose
set name lucy
set name ptg
set name gcw
set name gcw
AOF 檔案重寫的原理
AOF重寫並不需要對原有AOF檔案進行任何的讀取,寫入,分析等操作,這個功能是通過讀取伺服器當前的資料庫狀態來實現的。
# 假設伺服器對鍵list執行了以下命令
127.0.0.1:6379> RPUSH list "A" "B"
(integer) 2
127.0.0.1:6379> RPUSH list "C"
(integer) 3
127.0.0.1:6379> RPUSH list "D" "E"
(integer) 5
127.0.0.1:6379> LPOP list
"A"
127.0.0.1:6379> LPOP list
"B"
127.0.0.1:6379> RPUSH list "F" "G"
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "C"
2) "D"
3) "E"
4) "F"
5) "G"
127.0.0.1:6379>
結果分析
當前列表鍵list在資料庫中的值就為[“C”,“D”, “E”, “F”, “G”]。要使用盡量少的命令來記錄list鍵的狀態,最簡單的方式不是去讀取和分析現有AOF檔案的內容,,而是直接讀取list鍵在資料庫中的當前值,然後用一條RPUSH list “C” “D” “E” “F” "G"代替前面的6條命令。
結論
因為AOF如果記錄每一步操作,檔案會越來越大,通過AOF的重寫,可以縮小AOF檔案的尺寸。同樣可以達到資料還原效果。
- AOF重寫觸發的方式
觸發方式 | 描述 |
---|---|
手動觸發 | 通過呼叫bgrewriteaof手動觸發 |
自動觸發 | 同時滿足以下條件就觸發自動的AOF重寫操作: 1. 沒有RDB持久化/AOF持久化在執行,沒有bgrewriteaof在進行 2. 當前AOF檔案大小要大於redis.conf配置的auto-aof-rewrite-min-size大小 3. 當前AOF檔案大小和最後一次重寫後的大小之間的比率大於或者等於 指定的增長百分比。 (在配置檔案設定了auto-aof-rewrite-percentage引數,不設定預設為100%) |
演示-AOF手動重寫
-
關閉伺服器,刪除生成的aof和rdb檔案
-
執行以下命令
1. 從右邊新增一個鍵為list,值為A B
2. 從右邊新增 C
3. 從右邊新增 D E
4. 從左邊彈出一個元素
5. 從左邊彈出一個元素
6. 從右邊新增元素 F G
7. 顯示列表中的所有元素
-
輸入命令:bgrewriteaof,則aof被重寫
-
觀察目錄下會產生舊的的aof檔案
-
觀察伺服器上出現提示
1.5 演示-AOF自動重寫
-
關閉伺服器刪除生成的aof和rdb檔案
-
修改配置檔案如下:
# 大於原來的50%就自動重寫 auto-aof-rewrite-percentage 50 # 自動重寫的最小尺寸 auto-aof-rewrite-min-size 100b
-
帶配置檔案啟動伺服器: redis-server redis.windows.conf
-
執行如下命令:
1. 從右邊新增一個鍵為list,值為A B 2. 從右邊新增 C 3. 從右邊新增 D E 4. 從左邊彈出一個元素 5. 從左邊彈出一個元素 6. 從右邊新增元素 F G 7. 顯示列表中的所有元素
-
觀察目錄下會產生舊的的aof檔案
-
觀察伺服器上出現提示
AOF重寫原理:從資料庫中讀取鍵現在的值,然後用一條命令去記錄鍵值對,代替之前記錄該鍵值對的多個命令。
14_AOF和RDB常見問題-[★★]
1.1 實際開發中到底選擇哪種持久化機制?
下面是來自官方的建議:
通常,如果你要想提供很高的資料保障性,那麼建議你同時使用兩種持久化方式。
如果你可以接受災難帶來的幾分鐘的資料丟失,那麼你可以僅使用RDB。
很多使用者僅使用了AOF,但是我們建議,既然RDB可以時不時的給資料做個完整的快照,並且提供更快的重啟,所以最好還是也使用RDB。
因此,我們希望可以在未來(長遠計劃)統一AOF和RDB成一種持久化模式。
1.2 AOF和RDB是否可以同時使用?
可以同時使用,而且也是官方推薦的方式。
1.3 恢復資料時AOF和RDB哪個塊?
RDB更快:因為RDB持久化的是記憶體鍵值對的最終結果,直接載入記憶體即可。而AOF日誌檔案中儲存的是操作過的所有命令資訊,恢復資料時需要逐條執行命令。
15_Jedis的基本使用-[★★★★★]
- Jedis使用步驟
- 匯入jedis相關jar包
- 建立連線物件:Jedis物件
2.1 Redis資料庫地址
2.2 Redis資料庫埠號- 呼叫Jedis物件的方法對Redis資料庫執行增刪改查引數
方法名就是命令名字,方法引數就是命令引數
set name jack
set(“name”,“jack”)- 關閉連線釋放資源:close
- 示例程式碼
- 需求:使用Jedis向redis中新增string和list,讀取它們的值
/**
* 需求:使用Jedis向redis中新增string和list,讀取它們的值
實現步驟:
1. 匯入jedis相關jar包
2. 建立連線物件:Jedis物件
2.1 Redis資料庫地址
2.2 Redis資料庫埠號
3. 呼叫Jedis物件的方法對Redis資料庫執行增刪改查引數
方法名就是命令名字,方法引數就是命令引數
set name jack
set("name","jack")
4. 關閉連線釋放資源:close
*/
public class Demo01 {
public static void main(String[] args) {
// 建立連線物件:Jedis物件
// 引數1:Redis資料庫地址
// 引數2:Redis資料庫埠號
Jedis jedis = new Jedis("localhost", 6379);
// 儲存string型別資料
jedis.set("username", "小波");
// 儲存list型別的資料
// lpush 鍵 元素
// rpush 鍵 元素
jedis.lpush("list","a","b","c");
jedis.rpush("list","one","two","three");
// 獲得string型別的資料
String username = jedis.get("username"); // 小波
System.out.println(username);
// 獲得list型別的資料
List<String> list = jedis.lrange("list", 0, -1);
System.out.println("list = " + list);
System.out.println("list = " + list.getClass());// ArrayList
// 關閉連線釋放資源:close
jedis.close();
}
}
- 如何獲得Jedis連線物件
Jedis jedis = new Jedis("地址",埠號);
- Jedis物件與增刪改查字串相關的方法
jedis.set(key,value);
jedis.get(key);
jedis.del(key)
16_Jedis連線池建立和使用-[★★★★★]
- Jedis連線池相關API
JedisPoolConfig 配置類 | 功能說明 |
---|---|
JedisPoolConfig() | 建立一個配置物件,使用無參構造方法就可以了 |
void setMaxTotal() | 設定連線池最大的連線數 |
void setMaxWaitMillis() | 設定得到連線物件Jedis最長等待時間 |
JedisPool 連線池類 | 說明 |
---|---|
JedisPool(配置物件,伺服器名,埠號) | 建立連線池 引數1:上面的配置物件,引數2:伺服器名,引數3:6379 |
Jedis getResource() | 從連線池中得到一個Jedis連線物件 |
void close() | 連線池關閉方法,通常不關閉連線池 |
- 示例程式碼
/**
* 需求:建立Jedis連線池物件並獲得連線操作redis資料庫
實現步驟:
1. 建立連線池配置物件
1.1 最大連線數
1.2 最大等待時間
2. 建立連線池物件
2.1 配置物件
2.2 資料庫地址
2.3 資料庫埠號
3. 從連線池中獲取連線物件(Jedis物件)
4. 執行運算元據庫操作
5. 關閉連線:不是真正關閉而是放回連線池中等待複用
*/
public class Demo02 {
public static void main(String[] args) {
// 1. 建立連線池配置物件
JedisPoolConfig config = new JedisPoolConfig();
// 1.1 最大連線數
config.setMaxTotal(10);
// 1.2 最大等待時間
config.setMaxWaitMillis(2000);
// 2. 建立連線池物件
// 2.1 配置物件
// 2.2 資料庫地址
// 2.3 資料庫埠號
JedisPool jedisPool = new JedisPool(config, "localhost", 6379);
// 3. 從連線池中獲取連線物件(Jedis物件)
Jedis jedis = jedisPool.getResource();
// 4. 執行運算元據庫操作
jedis.sadd("set", "1","2","3","a","a");
Set<String> set = jedis.smembers("set");
System.out.println(set);
System.out.println(set.getClass()); // HashSet
// 5. 關閉連線:不是真正關閉而是放回連線池中等待複用
jedis.close();
}
}
- 連線池類叫什麼:JedisPool
- 常用的連線池引數有哪些?
最大連線數:maxTotal
最大等待時間:maxWaitMillis
17_Jedis連線池工具類實現-[★★★★★]
- 實現連線池工具類,通過工具類得到Jedis連線物件,配置引數寫在屬性檔案中。
- 呼叫工具類,對Redis資料庫進行操作。
-
JedisUtils工具類
-
實現步驟
- 在src目錄下建立連線池的工具類: jedis.properties
- 建立靜態成員變數JedisPool物件
- 在靜態程式碼塊中,讀取src下的配置檔案,得到ResourceBundle物件
- 得到上面的四個引數,其中host是字串型別,其它引數要轉成整數型別
- 例項化配置物件,例項化連線池物件
- 編寫靜態方法getJedis()返回Jedis物件
- jedis.properties配置檔案
# 主機名
host=localhost
# 埠號
port=6379
# 最大連線數
maxTotal=20
# 最長等待時間
maxWaitMillis=3000
- ResourceBundle類概述
java.util.ResourceBundle類是專門用於:讀取類路徑下Properties配置檔案的類。
java.util.ResourceBundle 類 | 功能 |
---|---|
static ResourceBundle getBundle(“配置基名”) | 通過靜態方法建立 ResourceBundle物件 引數:放在src 下.properties檔案。引數中不用寫副檔名,只要有主名就可以了 |
String getString(“鍵名”) | 通過鍵得到值 |
- JedisUtils類程式碼
/**
Jedis連線池工具類
*/
public class JedisUtil {
// 連線池物件
private static JedisPool jedisPool;
// 載入配置獲取資訊
static {
// ResourceBundle類是專門用於:讀取類路徑(src)下Properties配置檔案的類。
// 只需要檔名,不需要字尾名
ResourceBundle bundle = ResourceBundle.getBundle("jedis");
// 獲取地址
String host = bundle.getString("host");
// 獲取埠號
int port = Integer.parseInt(bundle.getString("port"));
// 獲取最大連線數
String maxTotal = bundle.getString("maxTotal");
// 獲取最大等待時間
String maxWaitMillis = bundle.getString("maxWaitMillis");
// 建立連線池配置物件
JedisPoolConfig config = new JedisPoolConfig();
// 設定最大連線數
config.setMaxTotal(Integer.parseInt(maxTotal));
// 設定最大等待時間
config.setMaxWaitMillis(Long.parseLong(maxWaitMillis));
// 根據配置物件建立連線池物件
jedisPool = new JedisPool(config, host, port);
}
/**
* 返回連線物件
* @return
*/
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
- 測試類程式碼
/**
* 測試Jedis連線池工具類
*/
public class Demo03 {
public static void main(String[] args) {
// 獲取連線物件
Jedis jedis = JedisUtil.getJedis();
// 建立Map集合
Map<String,String> map = new HashMap<>();
map.put("username", "小澤");
map.put("password", "1234");
map.put("age", "20");
// 儲存hash型別的資料
jedis.hmset("user1",map);
// 獲取hash型別的資料
Map<String, String> user1 = jedis.hgetAll("user1");
System.out.println(user1);
System.out.println(user1.getClass()); //
// 關閉連線釋放資源
jedis.close();
}
}
18_案例-非同步載入聯絡人-分析和環境準備-[★★★★★]
-
案例需求
訪問index.html頁面,點選頁面上的載入所有聯絡人按鈕,才使用ajax請求非同步載入所有聯絡人列表。使用者第一次訪問從mysql資料庫中獲取資料,以後都從redis快取裡面獲取。
-
資料準備
-
建立資料表
-- 聯絡人
create table contact (
id int primary key auto_increment,
name varchar(20) not null, -- 姓名
phone varchar(20), -- 電話
email varchar(50), -- 郵箱
birthday date -- 生日
);
insert into contact (name,phone,email,birthday) values
('孫悟空','13423431234','wukong@163.com', '1993-11-23'),
('豬八戒','13525678909','bajie@163.com', '1953-05-02'),
('白骨精','18642343123','xiaobai@163.com', '1943-03-12');
select * from contact;
- 實體類:Contact
/**
* 聯絡人實體類
*/
public class Contact {
private int id; //編號
private String name; //姓名
private String phone; //電話
private String email; //郵箱
private Date birthday; //生日
@Override
public String toString() {
return "Contact{" +
"id=" + id +
", name='" + name + '\'' +
", phone='" + phone + '\'' +
", email='" + email + '\'' +
", birthday=" + birthday +
'}';
}
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 String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
- 主配置檔案:sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--給資料型別取別名-->
<typeAliases>
<!-- 包掃描給類取別名,預設別名就是類名 -->
<package name="com.pkx.entity"/>
</typeAliases>
<!--配置資料庫連線引數-->
<environments default="mybatis">
<environment id="mybatis">
<!--事務管理器-->
<transactionManager type="JDBC"></transactionManager>
<!--配置資料來源-->
<dataSource type="pooled">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///day33"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 載入介面對映檔案 -->
<mappers>
<!-- 載入指定包(包括子包下)的所有介面對映對映檔案 -->
<package name="com.pkx.dao"/>
</mappers>
</configuration>
- SqlSessionUtils工具類
/**
* sqlSession工具類
*/
public class SqlSessionUtils {
// 1. sqlSessionFactory物件
private static SqlSessionFactory sqlSessionFactory;
// 2. 載入主配置檔案並獲得SqlSessionFactory物件
static {
try{
// 2.1 獲得位元組輸入流關聯sqlMapConfig.xml檔案
InputStream in = Resources.getResourceAsStream("sqlMapConfig.xml");
// 2.2 獲得SqlSessionFactoryBuilder物件
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 2.3 建立sqlSessionFactory物件
sqlSessionFactory = builder.build(in);
} catch(Exception e){
e.printStackTrace();
}
}
// 3. 返回一個sqlSession物件
public static SqlSession openSession(){
return sqlSessionFactory.openSession();
}
// 4. 返回Dao介面代理物件
public static <T> T getMapper(Class<T> interfaceClass){
// 建立代理物件並返回
return (T) Proxy.newProxyInstance(
SqlSessionUtils.class.getClassLoader(),
new Class[]{interfaceClass},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 獲得連線物件
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2. 獲得介面代理物件 ==》 (真實物件)
T dao = sqlSession.getMapper(interfaceClass);
// 4. 呼叫真實物件的方法
Object result = method.invoke(dao, args);
sqlSession.commit();
// 5. 關閉連線
sqlSession.close();
return result;
}
});
}
}
- redis配置檔案:redis.properties
# 連線池引數
# 最大連線數
maxTotal=10
# 最大等待時間
maxWaitMillis=3000
# 資料庫引數
# redis資料庫地址
host=localhost
# redis資料庫埠號
port=6379
- Redis工具類:RedisUtils
/**
* Redis連線池工具類
實現步驟:
1. 定義連線池物件靜態成員變數
2. 建立連線池物件:在靜態程式碼塊中完成
2.1 讀取配置檔案資訊
2.2 建立連線池配置物件
2.3 根據配置物件建立連線池物件
3. 提供公共的方法返回連線物件:Jedis
*/
public class JedisUtils {
// 1. 定義連線池物件靜態成員變數
private static JedisPool jedisPool = null;
// 2. 建立連線池物件:在靜態程式碼塊中完成
static {
// 2.1 讀取配置檔案資訊
// ResourceBundle類專門載入src目錄下的屬性檔案:只需要傳遞檔名,不需要字尾名
ResourceBundle bundle = ResourceBundle.getBundle("jedis");
// 獲得最大連線數
int maxTotal = Integer.parseInt(bundle.getString("maxTotal"));
// 獲得最大等待時間
long maxWaitMillis = Long.parseLong( bundle.getString("maxWaitMillis"));
// 獲得伺服器地址
String host = bundle.getString("host");
// 獲得伺服器埠號
int port = Integer.parseInt(bundle.getString("port"));
// 2.2 建立連線池配置物件
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxWaitMillis(maxWaitMillis);
// 2.3 根據配置物件建立連線池物件
jedisPool = new JedisPool(config, host, port);
}
// 3. 提供公共的方法返回連線物件:Jedis
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
19_案例-非同步載入聯絡人-伺服器端實現-[★★★★★]
- 資料訪問層:ContactDao
/**
* 資料訪問層介面
*/
public interface ContactDao {
// 1. 定義方法:查詢所有聯絡人資訊
// 引數:無引數
// 返回值:List<Contact>
@Select("select * from contact")
List<Contact> findAll();
}
- 業務層:ContactSerivce
/**
* 業務邏輯層
*/
public class ContactService {
// 獲取介面實現類
private ContactDao contactDao = SqlSessionUtils.getMapper(ContactDao.class);
/**
* 查詢所有聯絡人
*/
public String findAll(){
try{
// 1. 查詢redis資料庫獲取聯絡人資料
Jedis jedis = JedisUtil.getJedis();
String jsonStr = jedis.get("contactList");
if (jsonStr == null) {
System.out.println("從MySQL查詢資料...");
// 2. 從MySQL資料庫查詢聯絡人資料
List<Contact> contactList = contactDao.findAll();
// 2.1 將集合轉換為json字串
jsonStr = new ObjectMapper().writeValueAsString(contactList);
// 2.2 將聯絡人字串並儲存到Redis中
jedis.set("contactList", jsonStr);
} else {
System.out.println("從redis查詢資料....");
}
jedis.close();
// 3. 返回查詢到聯絡人資料
return jsonStr;
} catch(Exception e){
e.printStackTrace();
}
return null;
}
}
- 控制器:ContactServlet
/**
* 查詢聯絡人
*/
public class ContactServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 設定內容型別和編碼
response.setContentType("text/html;charset=utf-8");
// 獲得字元列印流
PrintWriter out = response.getWriter();
// 1. 建立業務層物件
ContactService cs = new ContactService();
// 2. 呼叫方法獲取聯絡人資料
String jsonStr = cs.findAll();
// 3. 返回聯絡人資料
out.println(jsonStr);
}
}
20_案例-非同步載入聯絡人-前端頁面實現-[★★★★★]
- 傳送非同步請求到伺服器請求聯絡人資料
- 將聯絡人資料顯示在表格中
- index.html實現程式碼
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>通訊錄管理</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<br>
<input id="btnLoad" type="button" class="btn btn-primary" value="載入聯絡人列表">
<input id="btnClear" type="button" class="btn btn-danger" value="清空聯絡人列表">
<hr>
<table class="table table-bordered table-hover table-striped">
<thead>
<tr class="success">
<th>編號</th>
<th>姓名</th>
<th>電話</th>
<th>郵箱</th>
<th>生日</th>
</tr>
</thead>
<tbody id="contacts">
</tbody>
</table>
</div>
</body>
<script>
// 監聽 載入聯絡人列表 點選
$("#btnLoad").click(function () {
// 傳送非同步請求獲取聯絡人資料
$.get({
url:"list", // 請求地址
dataType:"json", // 響應資料型別
success:function (jsonArray) { // 成功回撥
// 定義變數:用來拼接tr元素
var trs = "";
// 遍歷聯絡人陣列
$.each(jsonArray,function (index, contact) {
// 每一個聯絡人對應一行資料:一個tr標籤
trs += "<tr>" +
"<td>"+contact.id+"</td>"+
"<td>"+contact.name+"</td>"+
"<td>"+contact.phone+"</td>"+
"<td>"+contact.email+"</td>"+
"<td>"+contact.birthday+"</td>"+
"</tr>";
})
// 設定tbody元素內容
$("#contacts").html(trs);
},
error:function () { // 失敗回撥
alert("伺服器忙...")
}
});
});
$("#btnClear").click(function () {
$("#contacts").empty();
})
</script>
</html>
相關文章
- 【JAVA Web基礎學習】Day1JavaWeb
- 17_陣列陣列
- day02-Redis命令Redis
- 17_狀態模式模式
- day01-Redis入門Redis
- Web - Redis & JedisWebRedis
- day40-Python連線RedisPythonRedis
- day03-Redis的客戶端Redis客戶端
- Macaca UITest for Web IS Reday !!!MacUIWeb
- day4-3-redis常用命令Redis
- day2 Java NIOJava
- Java day10Java
- Java day14Java
- 17_深入解析Oracle undo原理(1)_transactionOracle
- java webJavaWeb
- Learning Java day1Java
- [Java筆記]day03Java筆記
- [Java筆記]day29Java筆記
- [Java筆記]day26Java筆記
- java day48——springMVCJavaSpringMVC
- JAVA學習day03Java
- Java 初學 day03Java
- Day148.Redis入門介紹、安裝、基本知識 -RedisRedis
- Java Web系列:Java Web 專案基礎JavaWeb
- Java學習—java-RedisJavaRedis
- Java Web現代化開發:Spring Boot + Mybatis + Redis二級快取JavaWebSpring BootMyBatisRedis快取
- 17_電話號碼的字母組合
- JAVA學習筆記—JAVA WEB(二)JAVA WEB核心(下)Java筆記Web
- redmon:Redis監控管理Web工具RedisWeb
- java Redis工具類JavaRedis
- redis+java操作RedisJava
- Java Redis多限流JavaRedis
- 學習筆記--Web基礎day04筆記Web
- 番茄工作法web應用 Do todayWeb
- 學習Java的Day05Java
- Day07——Java新手學習Java
- Day04——Java新手學習Java
- Day02——Java新手學習Java