lua web快速開發指南(6)
"資料庫"與"快取"的基本概念
資料庫與快取是服務端開發人員的必學知識點.
資料庫
"資料庫"是一種資訊記錄、存取的虛擬標記地點的集合統稱. 比如現實生活中, 我們經常會用到檔案櫃、書桌等等資料存取容器.
在對容器進行資料存取的時候, 我們會為每一層打上一個標籤表示一種分類項. 而這種在資料庫
中劃分子分類形成了表
的概念. 這就是我們通常所說的結構化資料庫
.
由於通常資料表之間可能會存在依賴關係, 某一(或者多)層通常可能會用於同一種用途. 這種用途將一層劃分為索引表, 二層劃分為分類表, 三層劃分為資料表.
實現這種功能與依賴關係的資料庫, 我們稱之為: 關係型資料庫
每當我們需要對資料進行結構化操作(查詢、增加、刪除、修改)的時候, 需要在計算機中用一種通俗易懂的語言表達方式
來進行助記. 這種結構化查詢語言稱之為SQL
.
快取
我們通常將資料儲存完畢後, 能通過指定或特定的一(多)種方式對資料進行操作. 在專案開發的初期, 這並沒有太大的問題.
但是隨著資料量的不斷增大, 在資料庫的記憶體中已經放不下這麼多資料. 我們的資料逐漸無法被載入到記憶體中: 只會在使用的時候才會進行(隨機)讀取. 而這會加大磁碟I/O.
我們知道通常磁碟的讀寫速度基本上會比記憶體讀寫慢幾個數量級(即使是SSD), 大量請求可能瞬間將磁碟IO佔滿並出現資料庫的CPU利用率低、記憶體頻繁進行修改/置換等問題.
為了解決這些問題, 出現了很多解決方案: 讀、寫分離、分表分庫等等. 雖然有了這些方案, 但是也同樣回引來新的問題: 主從同步、分散式事務等問題.
"快取"則是近十年興起的概念, 它的本質是一份資料結構化儲存在記憶體中的副本. 高階的快取
我們也可以將其稱之為記憶體資料庫
或NOSQL
(非關係型)資料庫.
"快取"也是一種"另類"解決資料庫問題點一種手段! 它通過豐富的資料結構擴充套件了資料模型的組合能力, 通過簡單的使用方法與高效的連線方式提供更好資料操作方式.
"快取"將查詢、更新較為頻繁的熱
資料組成一個集合載入進記憶體中, 較少使用的冷
這樣的方式配合資料庫都讀、寫分離與資料分割槽將資料合理的從一個數據集副本分散到多個數據集副本, 有效的減少效能問題點產生並且提升了整個業務系統的橫向擴充套件能.
DB庫
DB庫是cf框架封裝自MySQL 4.1協議實現的客戶端連線庫, 提供MySQL斷線重連、SQL重試、連線池等高階特性.
Cache
Cache庫是cf封裝自Redis 2.0協議實現的客戶端連線庫, 提供Redis斷線重連、命令重試、連線池等高階特性.
API學習
1. DB API
在使用下面的API之前, 請先確保已經匯入庫: local DB = require "DB"
.
1.1 DB:new(opts)
opts表的引數決定如何連線到MySQL, 表屬性如下:
host - MySQL主機名或IP地址(string型別).
port - MySQL埠號(int型別).
charset - MySQL字符集設定.
database - MySQL庫的名稱.
username - MySQL使用者賬戶(string型別).
password - MySQL使用者密碼(string型別).
max - MySQL的最大連線池大小(int型別).
這個方法返回一個新建立db物件
1.2 DB:connect()
開始連線MySQL. 連線成功返回True, 否則將會持續進行連線並且輸出連線失敗原因的日誌.
1.3 DB:query(SQL)
資料庫查詢語句呼叫方法, SQL為string型別的的一個標準SQL語句.
返回值為ret與err. 查詢成功ret為一個結果集陣列, 在發生錯誤時未nil, err為錯誤資訊.
2. Cache API
在使用下面的API之前, 請先確保已經匯入庫: local Cache = require "Cache"
.
2.1 Cache:new(opts)
opts表的引數決定如何連線到MySQL, 表屬性如下:
host - Redis主機名或IP地址(string型別).
port - Redis主機埠號(int型別).
auth - Redis主機設定的密碼, 預設為:nil.
db - Redis的資料庫設定.
max = 最大連線池大小(int型別).
此方法返回一個新建立的Cache物件.
2.2 Cache:connect()
開始連線Redis. 連線成功返回True, 否則將會持續進行連線並且輸出連線失敗原因的日誌.
2.3 Cache:API(...)
Cache支援大部分的redis API, 目前測試過多API在script/test_Cache.lua
檔案內部都有展示.
DB庫的操作流程
DB庫的操作與使用流程非常簡單, 其目標是簡化開發人員在業務編寫過程中的使用難點.
建立資料庫與資料表
啟動一個MySQL例項並且初始化完畢, 具體安裝與初始化方法根據平臺不同而不同, 這不再本文講解範圍內.
然後我們使用預設的root
使用者並且root
賬戶、密碼設定完畢. 這裡為了演示方便, 我們將root
密碼設定為: 123456789
.
建立一個叫cf_mall
的資料庫字符集編碼都設為utf-8
. 並且在cf_mall
資料庫中建立一個叫做cf_users
的表, 如下所示:
# 建立`cf_mall`資料庫
CREATE DATABASE IF NOT EXISTS `cf_mall` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
# 建立`cf_users`使用者表
CREATE TABLE IF NOT EXISTS `cf_mall`.`cf_users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '使用者ID',
`age` tinyint(3) unsigned NOT NULL COMMENT '使用者年齡',
`name` varchar(255) NOT NULL COMMENT '使用者名稱',
`username` varchar(255) NOT NULL COMMENT '使用者賬戶',
`password` varchar(255) NOT NULL COMMENT '使用者密碼',
`email` varchar(255) NOT NULL DEFAULT '' COMMENT '使用者郵箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
以上資料庫建立語句可以在一些MySQL GUI工具中直接執行.
測試DB庫的API寫入資料
現在, 讓我們利用上面學到的API嘗試將作者的資訊寫入進去. 同時為了避免密碼原文顯示, 我們需要使用crypt庫的base64方法將密碼進行編碼.
local crypt = require "crypt"
local DB = require "DB"
local db = DB:new {
host = "localhost",
port = 3306,
username = 'root',
password = 123456789,
database = "cf_mall",
charset = "utf8"
}
db:connect()
db:query(string.format([[
INSERT INTO `cf_mall`.`cf_users`
(`name`, `age`, `username`, `password`, `email`)
VALUE
('%s', '%s', '%s', '%s', '%s')
]],
'水果糖的小鋪子', '29', 'candymi', crypt.base64encode('123456789'), '[email protected]')
)
local ret, err = db:query("SELECT * FROM `cf_mall`.`cf_users` WHERE `name` = '水果糖的小鋪子'")
if not ret then
return print(ret, err)
end
return print('name:', ret[1].name, 'password:', ret[1].password, 'email:', ret[1].email)
檢查問題
最後我們檢查資料庫內是否已經寫入了我們需要儲存的資料. 如果使用的SQL有語法錯誤導致寫入失敗, 請使用print
檢查db:query
操作否出現錯誤.
同時我們在console控制檯上可以檢查是否輸出了我們剛才寫入到cf_users
的資訊.
Cache庫的操作流程
Cache庫擁有非常簡單的使用方法, 幾乎能執行所有Redis已提供的命令. 並且協議是二進位制安全的(binary safe).
啟動一個Redis例項
啟動並執行一個redis例項. 具體安裝與執行方法根據平臺不同而不同, 這不再本文講解範圍內.
並且這裡為了演示示例簡單, 我們將不設定任何auth
並且使用預設的db
.
將資料載入到Redis
我們將列出目前已知的一些知名大眾化語言, 然後將其寫入到Redis中.
local Cache = require "Cache"
local cache = Cache:new {
host = 'localhost',
port = 6379,
}
cache:connect()
local ok, msg = cache:rpush("languages", "C", "C++", "Java", "Golang", "Ruby", "Python", "PHP", "Lua")
if not ok then
return print(ok, msg)
end
print("當前language的總數為:", msg)
問題排查
最後, 讓我們用Redis自帶的命令列工具檢視是否真實寫入了資料.
[candy@MacBookPro:~] $ redis-cli
127.0.0.1:6379> lrange languages 0 -1
1) "C"
2) "C++"
3) "Java"
4) "Golang"
5) "Ruby"
6) "Python"
7) "PHP"
8) "Lua"
127.0.0.1:6379>
可以看到資料已經寫入進去. 如果傳送引數錯誤與語法發生錯誤, msg將會是您排查錯誤的有效資訊.
更多
更多API詳情請參考MySQL、Redis的使用文件並且在實際開發中進行體驗.
繼續學習
下一章節我們將繼續學習如何利用httpc庫