Home  >  Article  >  Backend Development  >  How to deal with Golang cache invalidation?

How to deal with Golang cache invalidation?

WBOY
WBOYOriginal
2024-06-02 17:09:02568browse

When dealing with cache invalidation in Golang, you can follow the following strategy: mark cache items with timestamps, and get new data when they expire. Using locks, the cache is locked when the coroutine obtains the cache item, and the cache is unlocked and new data is obtained when the cache item does not exist or expires.

如何处理 Golang 缓存失效的情况?

#How to deal with Golang cache failure?

When using cache in Golang programs, it is crucial to deal with cache invalidations to ensure data consistency and reliability. The following are two processing strategies:

1. Use timestamps

  • Associate cache items with timestamps.
  • When the cache item expires, get new data and update the cache.
type CacheItem struct {
    Value interface{}
    Timestamp time.Time
}

var cache = make(map[string]CacheItem)

func SetCache(key string, value interface{}) {
    cache[key] = CacheItem{Value: value, Timestamp: time.Now()}
}

func GetCache(key string) (interface{}, bool) {
    item, ok := cache[key]
    if ok && time.Since(item.Timestamp) < time.Second*30 {
        return item.Value, true
    }
    return nil, false
}

2. Use lock

  • When a coroutine obtains a cache item, lock the cache.
  • If the cache item does not exist or has expired, unlock the cache and get new data.
var cache = sync.Map{}

func SetCache(key string, value interface{}) {
    cache.Store(key, value)
}

func GetCache(key string) (interface{}, bool) {
    if value, ok := cache.Load(key); ok {
        return value, true
    }

    lock := sync.Mutex{}
    lock.Lock()
    defer lock.Unlock()

    if value, ok := cache.Load(key); ok {
        return value, true
    }

    newValue, err := fetchNewValue(key)
    if err == nil {
        cache.Store(key, newValue)
    }

    return newValue, err == nil
}

Practical Case

Suppose we are using cache in a RESTful API to store user details.

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "time"

    "github.com/go-redis/redis/v8"
)

var redisClient = redis.NewClient(&redis.Options{})

type User struct {
    ID   int
    Name string
}

func main() {
    // 添加缓存处理
    http.HandleFunc("/users/:id", func(w http.ResponseWriter, r *http.Request) {
        var user User
        id := r.URL.Path[len("/users/"):]

        // 尝试从缓存中获取用户数据
        cachedUser, ok := GetCache(id)
        if ok {
            // 缓存命中
            fmt.Fprintf(w, "User from cache: %+v", cachedUser)
            return
        }

        // 缓存未命中
        // 从数据库中获取用户数据
        err := db.Get(id, &user)
        if err != nil {
            // 数据库中不存在此用户
            fmt.Fprintf(w, "User not found")
            return
        }

        // 设置缓存,有效期为 30 秒
        SetCache(id, user, time.Second*30)
        fmt.Fprintf(w, "User from database: %+v", user)
    })

    http.ListenAndServe(":8080", nil)
}

func GetCache(key string) (User, bool) {
    result, err := redisClient.Get(key).Bytes()
    if err != nil {
        return User{}, false
    }

    var user User
    err = json.Unmarshal(result, &user)
    if err != nil {
        return User{}, false
    }

    return user, true
}

func SetCache(key string, user User, expiration time.Duration) {
    jsonBytes, err := json.Marshal(user)
    if err != nil {
        return
    }

    err = redisClient.Set(key, jsonBytes, expiration).Err()
    if err != nil {
        return
    }
}

The above is the detailed content of How to deal with Golang cache invalidation?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn