Go語言Redis API基本功能實踐

本來想着放棄Go了,沒想到人算不如天算,還是得繼續Go的學習和練習。由於之前提到的原因,又要把Java版本操作Redis也要遷移到Go版本了。

學習路線如下:

  1. Redis連接和基本操作
  2. 集合操作:hash、list、set和有序集合
  3. Redis stream

在整個學習過程中也對比了一下Go和Java版本的Redis,也發現Go語言在使用上是非常簡潔的,而且默認自帶Redis連接池。

按照我的習慣,一般都會都原聲的API進行封裝,例如之前寫到的Java版本Redis各類操作性能實踐:FunTester框架Redis壓測預備

由於Go已經解決了連接池的問題,封裝主要解決的就是默認返回值和異常處理。還沒在實際的工作中應用,只能先按照我寫Java的經驗來謝啦。目前還在學習Go語言簡易線程池的問題以及Java的其他問題,再疊加最近工作的確比較忙,所以最近學得少,寫的也少了。後續寫完Go的Redis教程以後,我會針對這些Redis的API進行性能測試實踐分享。

依賴

Go的依賴相對簡單,我使用的go.mod的方式,也可以通過將依賴下載到本地的path中。

github.com/go-redis/redis v6.15.9+incompatible

Redis API封裝

這裏發現Go版本的Redis庫相比Java版本都了幾個批量操作的API,都是以M開頭的,可能是因爲使用場景並不多,所以寫Java封裝方法的時候也沒注意,改天找找Java jedis的API。

package redis

import (
	"fmt"
	"funtester/base"
	"github.com/go-redis/redis"
	"log"
	"time"
)

//redis.Options 默認池大小爲10×cpu核數

type RedisBase struct {
	Host string
	db   int
	pool *redis.Client
}

// init 初始化類,創建連接池
//  @Description:
//
func NewRdisPool(host string, db int) RedisBase {
	redisBase := RedisBase{Host: host, db: db}
	redisBase.pool = redis.NewClient(&redis.Options{
		//Password: "",
		Addr:            host,
		DB:              0,
		MaxRetries:      3,
		MinRetryBackoff: 100 * time.Millisecond,
		DialTimeout:     5 * time.Second,
		WriteTimeout:    1 * time.Second,
		PoolSize:        200,
		MaxConnAge:      10 * time.Second,
		IdleTimeout:     8 * time.Second,
	})
	_, err := redisBase.pool.Ping().Result()
	if err != nil {
		log.Fatal("連接失敗", err)
	}
	log.Println("Redis 連接成功")
	ping := redisBase.Ping()
	if ping == "PONG" {
		log.Println("確認連接成功!")
	}
	return redisBase
}

func (r RedisBase) Ping() string {
	ping := r.pool.Ping()
	result, err := ping.Result()
	if err != nil {
		log.Println("確認連接失敗")
	}
	return result
}

// Keys 獲取所有的服務條件的keys列表
//  @Description:
//  @param patten
//  @return []string
//
func (r RedisBase) Keys(patten string) []string {
	result, err := r.pool.Keys(patten).Result()
	if err != nil {
		log.Printf("獲取keys: %s 失敗%s\n", patten, err.Error())
		return nil
	}
	return result
}

// Set 設置一個key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return string
//
func (r RedisBase) Set(key string, value interface{}, second time.Duration) string {
	result, err := r.pool.Set(key, value, time.Duration(second)*time.Second).Result()
	if err != nil {
		log.Printf("set:%s value: %s 失敗\n", key, value)
		return base.Empty
	}
	return result
}

// Get 查詢key的值
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Get(key string) string {
	result, err := r.pool.Get(key).Result()
	if err != nil {
		log.Printf("get:%s 失敗\n", key)
		return base.Empty
	}
	return result
}

// GetSet 設置一個key的值,並返回這個key的舊值
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) GetSet(key string, value interface{}) string {
	result, err := r.pool.GetSet(key, value).Result()
	if err != nil {
		log.Printf("set:%s value: %s 失敗\n", key, value)
		return base.Empty
	}
	return result
}

// SetNX 如果key不存在,則設置這個key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return bool
//
func (r RedisBase) SetNX(key string, value interface{}, second int64) bool {
	result, err := r.pool.SetNX(key, value, time.Duration(second)*time.Second).Result()
	if err != nil {
		log.Printf("set:%s value: %s 失敗\n", key, value)
		return false
	}
	return result
}

// MGet 批量查詢key的值
//  @Description:
//  @param key
//  @param value
//  @param expiration
//  @return bool
//
func (r RedisBase) MGet(keys ...string) []interface{} {
	result, err := r.pool.MGet(keys...).Result()
	if err != nil {
		log.Printf("獲取 keys : %s 失敗 %s", fmt.Sprint(keys), err.Error())
		return nil
	}
	return result
}

// MSet 批量設置key的值
//  @Description:
//  @param keys
//  @return string
//
func (r RedisBase) MSet(keys ...string) string {
	result, err := r.pool.MSet(keys).Result()
	if err != nil {
		log.Printf("設置 keys : %s 失敗 %s", fmt.Sprint(keys), err.Error())
		return base.Empty
	}
	return result
}

// Incr 針對一個key的數值進行遞增操作
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Incr(key string) int64 {
	result, err := r.pool.Incr(key).Result()
	if err != nil {
		log.Printf("自增 key: %s 失敗 %s", key, err.Error())
		return base.TEST_ERROR
	}
	return result
}

// IncrBy 針對一個key的數值進行遞增操作
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) IncrBy(key string, value int64) int64 {
	result, err := r.pool.IncrBy(key, value).Result()
	if err != nil {
		log.Printf("自增 key: %s 失敗 %s", key, err.Error())
		return -1
	}
	return result
}

// Decr 針對一個key的數值進行遞減操作
//  @Description:
//  @param key
//  @return string
//
func (r RedisBase) Decr(key string) int64 {
	result, err := r.pool.Decr(key).Result()
	if err != nil {
		log.Printf("自減 key: %s 失敗 %s", key, err.Error())
		return base.TEST_ERROR
	}
	return result
}

// DecrBy 針對一個key的數值進行遞減操作
//  @Description:
//  @param key
//  @param value
//  @return string
//
func (r RedisBase) DecrBy(key string, value int64) int64 {
	result, err := r.pool.DecrBy(key, value).Result()
	if err != nil {
		log.Printf("自減 key: %s 失敗 %s", key, err.Error())
		return base.TEST_ERROR
	}
	return result
}

// Del 刪除key操作,支持批量刪除
//  @Description:
//  @param keys
//  @return int64
//
func (r RedisBase) Del(keys ...string) int64 {
	result, err := r.pool.Del(keys...).Result()
	if err != nil {
		log.Printf("刪除 key: %s 失敗 %s", fmt.Sprintln(keys), err.Error())
		return base.TEST_ERROR
	}
	return result
}

// Expire 設置key的過期時間,單位秒
//  @Description:
//  @param key
//  @param second
//  @return bool
//
func (r RedisBase) Expire(key string, second int64) bool {
	result, err := r.pool.Expire(key, time.Duration(second)*time.Second).Result()
	if err != nil {
		log.Printf("設置 key: %s 過期時間失敗 %s", fmt.Sprintln(key), err.Error())
		return false
	}
	return result
}

API演示

基本上就是照着教程寫完,然後再轉成封裝好的API實踐,感覺更加清爽了,基本和Java版本的使用體驗一致。

package test

import (
	"funtester/db/redis"
	"funtester/ftool"
	"github.com/go-playground/assert/v2"
	"log"
	"strconv"
	"testing"
)

var pool = redis.NewRdisPool("127.0.0.1:6379", 1)

func TestRedis(t *testing.T) {
	var str = "FunTester"
	set := pool.Set("fun", str, 0)
	log.Print(set)
	get := pool.Get("fun")
	assert.Equal(t, get, str)
	getSet := pool.GetSet("fun", str+ftool.RandomStr(3))
	log.Println(getSet)
	pool.Set("aa", "32342", 0)
	mGet := pool.MGet("fun", "aa")
	for i, i2 := range mGet {
		log.Printf("index :%d  value : %s\n", i, i2)
	}
	pool.Expire("fun", 300)
	keys := pool.Keys("fu*")
	for i, key := range keys {
		log.Printf("index : %d, key : %s", i, key)
	}
	key := str + strconv.Itoa(ftool.RandomInt(1000))
	pool.SetNX(key, "32432", 100)
	log.Println(pool.Get(key))
	log.Println("22222")
	i := pool.MGet(str, key)
	for _, i3 := range i {
		log.Println(i3)
	}
	pool.MSet("aa", "111", "aabbbb", "22222")
	pool.Incr("sum")
	pool.IncrBy("sum", 10)
	log.Println(pool.Get("sum"))
	strings := pool.Keys("aa*")
	for _, s := range strings {
		log.Println(s)
	}
	pool.Decr("aa")
	pool.Expire("sum", 100)
}

控制檯輸出

相對比較單調,只是確認一下實際效果,總體打印信息比較亂,不少方法不夠熟練,各位將就看看。

2022/06/18 21:31:06 Redis 連接成功
2022/06/18 21:31:06 確認連接成功!
=== RUN   TestRedis
2022/06/18 21:31:06 OK
2022/06/18 21:31:06 FunTester
2022/06/18 21:31:06 index :0  value : FunTesterc3F
2022/06/18 21:31:06 index :1  value : 32342
2022/06/18 21:31:06 index : 0, key : fun
2022/06/18 21:31:06 32432
2022/06/18 21:31:06 22222
2022/06/18 21:31:06 <nil>
2022/06/18 21:31:06 32432
2022/06/18 21:31:06 56
2022/06/18 21:31:06 aa
2022/06/18 21:31:06 aabbbb
2022/06/18 21:31:06 aaaa
--- PASS: TestRedis (0.00s)
PASS

BUG挖掘機·性能征服者·頭頂鍋蓋

閱讀原文,跳轉我的倉庫地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章