首頁  >  文章  >  後端開發  >  Golang中使用快取加速資料庫存取效率的實踐。

Golang中使用快取加速資料庫存取效率的實踐。

WBOY
WBOY原創
2023-06-20 10:12:101517瀏覽

Golang中使用快取加速資料庫存取效率的實踐

隨著Web應用越來越複雜,對資料庫的存取也變得越來越頻繁。而存取資料庫通常是非常耗時的操作,特別是在資料量較大的情況下。為了提高存取資料庫的效率,可以採用諸如快取等策略來優化資料庫存取。

本文將介紹Golang中如何使用快取加速資料庫存取的實踐。我們將使用Golang作為開發語言,Redis作為快取伺服器,MySQL作為資料庫伺服器進行實驗。

1.建造環境

在開始之前,我們需要搭建好環境。首先安裝Golang以及MySQL和Redis伺服器,這裡不再贅述。

然後在Golang中安裝本地Redis和MySQL的Go驅動程式:

go get github.com/go-redis/redis/v8
go get github.com/go-sql-driver/mysql

2.編寫程式碼

接下來,我們編寫程式碼以實現快取加速資料庫存取。

首先是資料庫存取的程式碼。我們定義了一個叫做DB的全域變量,用於連接MySQL。然後,我們定義了一個函數getUserByID,用於從MySQL中查詢一個使用者的資訊:

package main
 
import (
   "database/sql"
   "fmt"
   "log"
 
   _ "github.com/go-sql-driver/mysql"
)
 
var DB *sql.DB
 
type User struct {
   ID       int
   Username string
   Password string
   Age      int
}
 
func init() {
   db, err := sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/test?charset=utf8")
   if err != nil {
      log.Fatal("Open mysql failed,err:", err)
      return
   }
   DB = db
   fmt.Println("Connect to mysql success")
}
 
func getUserByID(id int) (*User, error) {
   var user User
   query := "SELECT id, username, password, age FROM users WHERE id=?"
   err := DB.QueryRow(query, id).Scan(&user.ID, &user.Username, &user.Password, &user.Age)
   if err != nil {
      log.Println(err)
      return nil, err
   }
   return &user, nil
}

然後,我們在這個getUserByID函數中加入了快取邏輯。具體而言,我們首先透過getUserByID函數嘗試從Redis快取中讀取請求的使用者資訊。如果Redis中沒有該使用者的資訊記錄,則從MySQL中讀取使用者資訊,並將其存入Redis以供下次存取。如果使用者資訊在Redis中有記錄,則直接從Redis傳回使用者資訊:

package main
 
import (
   "database/sql"
   "encoding/json"
   "fmt"
   "log"
   "strconv"
 
   "github.com/go-redis/redis/v8"
   _ "github.com/go-sql-driver/mysql"
)
 
var DB *sql.DB
var RedisClient *redis.Client
 
type User struct {
   ID       int
   Username string
   Password string
   Age      int
}
 
func init() {
   db, err := sql.Open("mysql", "root:password@tcp(127.0.0.1:3306)/test?charset=utf8")
   if err != nil {
      log.Fatal("Open mysql failed,err:", err)
      return
   }
   DB = db
   fmt.Println("Connect to mysql success")
 
   RedisClient = redis.NewClient(&redis.Options{
      Addr: "127.0.0.1:6379",
   })
   pong, err := RedisClient.Ping(RedisClient.Context()).Result()
   if err != nil {
      panic(err)
      return
   }
   fmt.Println("Connect to redis success: ", pong)
}
 
func getUserByID(id int) (*User, error) {
   var user User
   key := "user-" + strconv.Itoa(id)
 
   // 1.尝试从Redis中读取用户信息
   val, err := RedisClient.Get(RedisClient.Context(), key).Result()
   if err == redis.Nil {
      fmt.Println("Cache miss")
   } else if err != nil {
      log.Println("Get from Redis fail:", err)
   } else {
      fmt.Println("Get from Redis:", val)
      if err := json.Unmarshal([]byte(val), &user); err != nil { // 将json字符串转换为结构体
         log.Panicln("Unmarshal to user fail:", err)
      }
      return &user, nil
   }
 
   // 2.如果Redis中没有,从MySQL中查询
   query := "SELECT id, username, password, age FROM users WHERE id=?"
   err = DB.QueryRow(query, id).Scan(&user.ID, &user.Username, &user.Password, &user.Age)
   if err != nil {
      log.Println(err)
      return nil, err
   }
 
   // 3.然后更新Redis缓存
   val, err = json.Marshal(user) // 将结构体转换为json字符串
   if err != nil {
      log.Panicln("Marshal user fail:", err)
   }
   err = RedisClient.Set(RedisClient.Context(), key, val, 0).Err()
   if err != nil {
      log.Panicln("Cache to Redis fail:", err)
   }
   return &user, nil
}

3.測試

我們完成了快取邏輯的編寫。現在我們來測試一下這份程式碼,看看運行效果如何。

首先,我們測試程式第一次查詢使用者資訊需要從MySQL中讀取:

func main() {
   id := 1
   user, err := getUserByID(id)
   if err != nil {
      log.Fatal(err)
      return
   }
   fmt.Printf("User info: id=%d, username=%s, password=%s, age=%d
",
      user.ID, user.Username, user.Password, user.Age)
}

運行程序,輸出如下:

Cache miss
User info: id=1, username=kirito, password=123456, age=18

可以看到程式從MySQL中取出了用戶訊息,並將其存入了Redis快取中。

第二次查詢同樣的使用者後,程式將從Redis讀取使用者資訊而不是存取MySQL資料庫:

func main() {
   id := 1
   user, err := getUserByID(id)
   if err != nil {
      log.Fatal(err)
      return
   }
   fmt.Printf("User info: id=%d, username=%s, password=%s, age=%d
",
      user.ID, user.Username, user.Password, user.Age)
}

運行程序,輸出如下:

Get from Redis: {"ID":1,"Username":"kirito","Password":"123456","Age":18}
User info: id=1, username=kirito, password=123456, age=18

可以看到程式直接從Redis讀取了用戶信息,而沒有存取MySQL資料庫,這證明了快取的實用性。

總結

在本文中,我們介紹了Golang中使用Redis快取機制來優化資料庫存取效率的實踐。透過編寫getUserByID函數,我們在查詢使用者資訊時首先嘗試從Redis讀取資訊以加速查詢速度,如果Redis中沒有該使用者資訊則從MySQL讀取並將其存入Redis。將資料進行快取後,程式在多次存取相同資料時,可以直接從快取中讀取,而不需要每次都去存取資料庫。

要注意的是,快取的使用需要避免髒資料產生。對於資料的CRUD操作,快取也需要跟隨資料進行操作,以確保資料在快取和資料庫中的一致性。

總的來說,使用快取機制可以大幅提高程式的效能,並且在處理大量資料的時候特別有效。這種策略在高並發系統中也非常實用,建議開發者嘗試。

以上是Golang中使用快取加速資料庫存取效率的實踐。的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn