帶你瞭解使用 Go 怎樣實現二級緩存
一、需求
-
實現二級緩存
-
程序運行起來後提示:“請輸入命令:”,如果輸入
getall
,查詢並顯示所有人員的信息 -
第一次時查詢
mysql
並將結果緩存在redis
,設置 60 秒的過期時間 -
以後的每次查詢,如果
redis
有數據就從redis
加載,沒有則重複上一步的操作
二、實現連接 Mysql 並執行查詢語句
先實現需求二,當輸入命令getall
時,查詢並顯示所有人員的信息。
package main
import (
"fmt"
_"github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
type Human struct {
Name string `db:"name"`
Age int `db:"age"`
}
func main() {
var cmd string
for{
fmt.Println("請輸入命令:")
fmt.Scan(&cmd)
switch cmd{
case "getall":
//顯示所有人的信息
GetAllPeople()
case "exit":
//退出程序
goto GAMEOVER
default:
fmt.Println("輸入的命令有誤,請重新輸入!")
}
}
GAMEOVER:
fmt.Println("GAME OVER")
}
func GetAllPeople() {
fmt.Println("allPeople")
//先嚐試拿緩存
GetPeopleFromRedis()
db, _ := sqlx.Connect("mysql", "root:123456@tcp(localhost:3306)/mydb")
defer db.Close()
var people []Human
err := db.Select(&people, "select name,age from person")
if err!=nil{
fmt.Println("查詢失敗!err=",err)
}
fmt.Println(people)
CachePeople2Redis(people)
}
第一步還是導包,需要在 mysql 驅動包前面加上下劃線_
,因爲它只是一個驅動文件,並不需要在代碼中調用它的有關 API 接口.
接下來的這個結構體中後面的db:"name"
db:"age"
一定要加反單引號,否則運行時會報錯。
type Human struct {
Name string `db:"name"`
Age int `db:"age"`
}
然後 main 函數里面都是一些基本語法知識,用了switch
和goto
這兩個內容。
接下來就是連接數據庫了,這裏要用到數據庫擴展包Sqlx
,Sqlx包
其實最大最大的優點是在查詢方面,也就是使用 select 時優化得比較好。比原來的使用查詢方便了不止一點。
db, _ := sqlx.Connect("mysql", "root:123456@tcp(localhost:3306)/mydb")
driverName:mysql, 表示驅動器的名稱是 mysql 也就上面 "github.com/go-sql-driver/mysql" 導入的驅動器。
dataSourceName 是 root:123456@tcp(localhost:3306)/mydb 它的含義是 賬戶名: 密碼 @tcp(ip: 端口)/ 數據庫名稱。
將緩存查詢結果到 Redis, 就是通過這個函數 CachePeople2Redis(people)。
三、寫一個錯誤處理函數
func HandleError(err error,why string) {
if err != nil{
fmt.Println(err,why)
os.Exit(1)
}
}
因爲後面需要處理很多錯誤,而錯誤處理也是 GO 的一個特性,所以我們這先寫一個錯誤處理函數。
四、設置二級緩存
func CachePeople2Redis(people []Human) {
conn, _ := redis.Dial("tcp", "localhost:6379")
defer conn.Close()
for _,human := range people{
humanStr := fmt.Sprint(human)
_, err := conn.Do("rpush", "people", humanStr)
if err != nil{
fmt.Println("緩存失敗(rpush people),err=",err)
return
}
}
_, err := conn.Do("expire", "people", 66)
if err!=nil{
HandleError(err,"@expire people 60")
}
fmt.Println("緩存成功!")
}
redis.Dial()
這個函數是用來連接 redis 的,需要給定網絡協議和 IP 地址及端口號,redis 的端口號默認爲 6379.
defer conn.Close()
表示延時結束與 redis 的連接,爲了節省系統的 io 資源,需要及時關閉連接!剛入門時我們很容易忘記這個,需要我們養成習慣!
conn.Do()
是用來執行數據庫命令的,第一個參數是命令名,後面的參數是數據庫命令的參數。它返回的結果中 reply 是字節數組 []byte 類型,需要根據具體的業務類型進行數據類型轉換。
這段代碼先將 people 數組中的每一個 human 放入到 redis 的 people 列表中。然後再執行 expire 命令,將列表設置過期時間。
執行成功!下面是運行結果:
請輸入命令:
getall
allPeople
[{大揚 21} {小飛 21} {大紅袍 1} {小芳 18}]
緩存成功!
請輸入命令:
然後去看看數據庫裏面存進去沒有。
127.0.0.1:6379> lrange people 0 -1
1) "{\xe5\xa4\xa7\xe6\x89\xac 21}"
2) "{\xe5\xb0\x8f\xe9\xa3\x9e 21}"
3) "{\xe5\xa4\xa7\xe7\xba\xa2\xe8\xa2\x8d 1}"
4) "{\xe5\xb0\x8f\xe8\x8a\xb3 18}"
過了一分鐘之後,再查看 redis 數據庫內的數據。
127.0.0.1:6379> lrange people 0 -1
(empty list or set)
已經消失了。
再寫一個函數:
func GetPeopleFromRedis() (peopleStrs []string) {
//連數據庫
conn, _ := redis.Dial("tcp", "localhost:6379")
//延遲關閉
defer conn.Close()
//執行命令
reply, err := conn.Do("lrange", "people", 0, -1)
//處理錯誤
HandleError(err,"@lrange people 0 -1")
//類型轉換
peopleStrs, err = redis.Strings(reply, err)
//打印結果
fmt.Println("緩存拿取結果:",peopleStrs,err)
return
}
如果redis
裏面有就不需要從mysql
裏面取數據了。直接從redis
裏面利用lrange
命令來獲取 people 的所有值。
原文地址:https://juejin.cn/post/6994600836101832741
歡迎關注 全棧公園 公衆號,在公衆號中輸入 開源交流 進羣
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/AmuYewcCdbk2N0hAa-4_2g