帶你瞭解使用 Go 怎樣實現二級緩存

一、需求

二、實現連接 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 函數里面都是一些基本語法知識,用了switchgoto這兩個內容。

接下來就是連接數據庫了,這裏要用到數據庫擴展包SqlxSqlx包其實最大最大的優點是在查詢方面,也就是使用 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