成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在 Go 項目中使用 Redis 的幾個實用建議

開發 Redis
今天來聊一聊 Redis,主要是聊一些在 Go 項目中使用go-redis 代碼上的一些建議。

在上代碼之前我還是要廢話幾句,在大家開發需求用到Redis時一定要多想個兩分鐘 "我是不是把Redis當數據庫用了?" 因為數據在數據庫和Redis里存兩份就就得考慮它們的一致性怎么維護,賊麻煩,而這個一致性不做上線后還經常會出BUG,所以不是必要我一般不用Redis。

需要過期的數據肯定是要存Redis的,比如用戶的 token 之類的數據,否則存在數據庫里還得寫定時任務來實現token過期刪除的功能 。

PS:Token 別用JWT,最好自己實現一套,后面會跟大家聊一些這方面的經驗。

Redis 客戶端的初始化

Redis 客戶端的初始化,這個我建議還是在做好的Redis分層里通過 Go 自帶的init 函數來實現初始化,別在整個項目的main方法里一個個調用自己定制化的 InitRedis 之類的方法去實現。

這個有人問為什么? 很簡單因為Go的那些個init函數是在main方法之前執行的,就是被設計用來做初始化工作的。而且我們也不必擔心初始化順序的問題,被依賴地最深層次的包會最先被初始化。

package cache

......

var redisClient *redis.Client

func Redis() *redis.Client {
 return redisClient
}

func init() {
 redisClient = redis.NewClient(&redis.Options{
  Addr:         config.Redis.Addr,
  Password:     config.Redis.Password,
  DB:           config.Redis.DB,
  PoolSize:     config.Redis.PoolSize,
 })

 if err := redisClient.Ping(context.Background()).Err(); err != nil {
  // 連接不上redis 讓項目停止啟動
  panic(err)
 }
}

go-redis的客戶端初始化完成后,如果不手動執行Ping 或者是其他Redis操作的話是不會真的去連接Redis服務器的,如果你希望在項目啟動時嘗試連接Redis服務器,失敗則停止啟動。那么就加一個Ping測試,連接不上用panic 讓程序直接退出。

 if err := redisClient.Ping(context.Background()).Err(); err != nil {
  // 連接不上redis 讓項目停止啟動
  panic(err)
 }

當然如果你的程序有Redis連接不上讀數據庫的兜底策略,可以選擇在項目啟動的時候不進行Redis連接性的測試。

Redis Key 的命名Tips

我在項目中被 Redis 搞的頭大最多的情況是,有的人特別喜歡在A項目里緩存了個什么數據,然后下游的B項目再去讀這個數據,根據緩存里數據的狀態執行不同的邏輯分支。

這個使用場景沒問題,但是很多時候Redis 的 Key 攜帶的信息實在是太少,有的時候我在項目B里面DEBUG,查問題看到從Redis里讀取到的數據跟預想的不一樣,但是我在整個項目里也沒發現這個緩存從哪存的。 這個時候如果你們團隊的微服務拆地足夠好(bushi,服務比人還多。。。。。。 會有當場去世的感覺。

別笑,項目比開發多是真事兒,因為以前50多人的團隊造了10多個20多個項目,現在能給你縮減到5個人都不是怪事兒。

所以我們在使用Redis的時候,最好把Key 放在項目里統一的地方進行管理,同時在命名上加上包含業務、項目、模塊信息的前綴名,通過它們在查問題的時候我們最起碼能快速定位到緩存是哪個項目寫進去的。

存結構化數據,用String 還是 Hash

用Redis時還有一個問題,就是很多時候我們的結構數據是JSON序列化后存到 Redis 的 String 類型中去的,Redis中還有Hash類型類似于編程語言里的哈希Map。

那么我們存儲結構數據的時候應該存到 String 還是 Hash 中呢?答案是都行—— 僅從代碼層面講,哈哈哈......,但是前提是DAO查詢方法返回做好明確的類型聲明,像下面這樣:

unc SetOrder(ctx context.Context, order *do.Order) error {
 jsonDataBytes, _ := json.Marshal(order)
 redisKey := fmt.Sprintf(enum.REDIS_KEY_ORDER_DETAIL, order.OrderNo)
 _, err := Redis().Set(ctx, redisKey, jsonDataBytes, 0).Result()
 if err != nil {
  log.New(ctx).Error("redis error", "err", err)
  return err
 }

 return nil
}

func GetOrder(ctx context.Context, orderNo string) (*do.Order, error) {
 redisKey := fmt.Sprintf(enum.REDIS_KEY_DEMO_ORDER_DETAIL, orderNo)
 jsonBytes, err := Redis().Get(ctx, redisKey).Bytes()
 if err != nil {
  log.New(ctx).Error("redis error", "err", err)
  return nil, err
 }
 data := new(do.Order)
 json.Unmarshal(jsonBytes, &data)
 return data, nil
}

如果你想從 Redis 層面把數據的結構化體現的更好一點,那么就用Hash,這里需要注意的是go-redis支持把結構體數據直接存到Redis Hash 的前提是要在結構體字段的tag 上攜帶 redis 標識。

這里有官方對這塊的的解釋。

Playing struct With "redis" tag. type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }

HSet("myhash", MyHash{"value1", "value2"})

For struct, can be a structure pointer type, we only parse the field whose tag is redis. 

If you don't want the field to be read, you can use the `redis:"-"` flag to ignore it, or you don't need to set the redis tag. 

For the type of structure field, we only support simple data types: string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ), if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface. 

所以我們的數據結構必須像下面這樣定義:

type DummyOrder struct {
 OrderNo string `redis:"orderNo"`
 UserId  int64  `redis:"userId"`
}

然后go-redis 才能把數據通過HSET 存到Redis的Hash中,而直接讀取Hash數據到比如上面定義的結構體的時候,需要用到go-redis 提供的HGetAll 和 Scan 方法,同理接受數據的結構體的字段也需要在tag中攜帶redis標識,不帶這個標識Scan方法不會把數據填充到字段上。

總結

Redis的使用Tips上就先講這么多,歡迎大家在評論區里補充,另外Go項目中用到redis時也有人會選擇用redigo,我在工作時也用過,不過都是集成給我的一些老項目,不知道是不是redigo這個庫出的時間更早。

責任編輯:趙寧寧 來源: 網管叨bi叨
相關推薦

2024-11-28 09:54:34

項目架構模型

2009-06-24 17:34:58

使用JSF的經驗

2024-10-06 13:41:25

2015-08-03 11:45:37

storyboard

2018-08-21 09:00:30

Linuxtop命令

2024-12-11 09:13:00

2013-06-25 09:52:32

GoGo語言Go編程

2024-02-04 00:00:00

Go貨幣接口

2024-10-17 08:58:31

2023-11-27 19:39:46

Goprotobuf

2010-04-29 12:46:42

Oracle SQL

2024-04-01 00:00:00

Redis緩存服務消息隊列

2023-11-30 09:00:00

TypeScript開發

2024-09-10 09:05:12

SpringREST并發

2018-05-02 09:18:17

Linux技巧嵌入式

2024-07-03 13:03:30

Spring注解項目

2017-07-04 19:02:17

ReacRedux 項目

2023-10-28 16:22:21

Go接口

2021-11-29 22:59:34

Go Dockertest集成

2023-05-15 08:32:45

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99亚洲精品| 久久久久国产一区二区三区 | 国产高清一区 | 欧美视频1区 | 日韩三级 | 欧美福利视频 | 国产午夜精品一区二区三区四区 | 成人福利网站 | 天堂网中文字幕在线观看 | 国产精品欧美一区二区三区不卡 | 国产精品一区二区三区四区 | aaaa一级毛片 | 亚洲天堂一区 | 精品国产一区二区三区久久久蜜月 | 成人在线不卡 | 日本激情一区二区 | 国产日韩欧美一区二区 | 日韩成人一区 | 欧美一区二区三区在线视频 | 成人一区二区三区在线观看 | 欧美日韩国产精品一区 | 国产精品国产成人国产三级 | 狠狠色香婷婷久久亚洲精品 | 国产一二三区精品视频 | 成人三区四区 | 亚洲高清网 | 乱一性一乱一交一视频a∨ 色爱av | 亚洲欧美一区二区三区在线 | 日韩欧美在 | 国产精品日韩欧美一区二区三区 | 性欧美精品一区二区三区在线播放 | 请别相信他免费喜剧电影在线观看 | 精品久久亚洲 | 欧美一区二区三区在线 | 99免费看 | 在线日韩不卡 | 欧美a区| 国产精久久久久久 | 久久aⅴ乱码一区二区三区 亚洲国产成人精品久久久国产成人一区 | 草b视频 | 天天碰日日操 |