redis.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // Package redis 工具包
  2. package redis
  3. import (
  4. "context"
  5. "errors"
  6. "sync"
  7. "time"
  8. "github.com/redis/go-redis/v9"
  9. "github.com/runningwater/gohub/pkg/logger"
  10. )
  11. // Client Redis 服务
  12. type Client struct {
  13. Client *redis.Client
  14. Context context.Context
  15. }
  16. // Ping 测试 Redis 连接
  17. // 通过 Ping 方法测试 Redis 连接是否正常
  18. func (rds *Client) Ping() error {
  19. _, err := rds.Client.Ping(rds.Context).Result()
  20. return err
  21. }
  22. // Set 设置 Redis 键值对, 并设置过期时间
  23. func (rds *Client) Set(key string, value any, expiration time.Duration) bool {
  24. if err := rds.Client.Set(rds.Context, key, value, expiration).Err(); err != nil {
  25. logger.ErrorString("Redis", "Set", err.Error())
  26. return false
  27. }
  28. return true
  29. }
  30. // Get 获取 Redis 键值对
  31. func (rds *Client) Get(key string) string {
  32. val, err := rds.Client.Get(rds.Context, key).Result()
  33. if err != nil {
  34. logger.ErrorString("Redis", "Get", err.Error())
  35. return ""
  36. }
  37. return val
  38. }
  39. // Has 检查 Redis 中是否存在某个键
  40. func (rds *Client) Has(key string) bool {
  41. _, err := rds.Client.Get(rds.Context, key).Result()
  42. if err != nil {
  43. if errors.Is(err, redis.Nil) {
  44. logger.ErrorString("Redis", "Has", err.Error())
  45. }
  46. return false
  47. }
  48. return true
  49. }
  50. // Del 删除 Redis 中的键, 支持多个 key 传参
  51. func (rds *Client) Del(keys ...string) bool {
  52. if err := rds.Client.Del(rds.Context, keys...).Err(); err != nil {
  53. logger.ErrorString("Redis", "Del", err.Error())
  54. return false
  55. }
  56. return true
  57. }
  58. // FlushDb 清空 Redis 数据库
  59. func (rds *Client) FlushDb() bool {
  60. if err := rds.Client.FlushDB(rds.Context).Err(); err != nil {
  61. logger.ErrorString("Redis", "FlushDb", err.Error())
  62. return false
  63. }
  64. return true
  65. }
  66. // Increment 当参数只有 1 个时,增加 Redis 中的键值对增加 1
  67. // 当参数有 2 个时,第一个参数为 Key,第二个参数为增加的值 int64 类型
  68. func (rds *Client) Increment(args ...any) bool {
  69. switch len(args) {
  70. case 1:
  71. key := args[0].(string)
  72. if err := rds.Client.Incr(rds.Context, key).Err(); err != nil {
  73. logger.ErrorString("Redis", "Increment", err.Error())
  74. return false
  75. }
  76. case 2:
  77. key := args[0].(string)
  78. value := args[1].(int64)
  79. if err := rds.Client.IncrBy(rds.Context, key, value).Err(); err != nil {
  80. logger.ErrorString("Redis", "Increment", err.Error())
  81. return false
  82. }
  83. default:
  84. logger.ErrorString("Redis", "Increment", "参数错误, 只能传入 1 或 2 个参数")
  85. return false
  86. }
  87. return true
  88. }
  89. // Decrement 当参数只有 1 个时,减少 Redis 中的键值对减少 1
  90. // 当参数有 2 个时,第一个参数为 Key,第二个参数为减少的值 int64 类型
  91. func (rds *Client) Decrement(args ...any) bool {
  92. switch len(args) {
  93. case 1:
  94. key := args[0].(string)
  95. if err := rds.Client.Decr(rds.Context, key).Err(); err != nil {
  96. logger.ErrorString("Redis", "Decrement", err.Error())
  97. return false
  98. }
  99. case 2:
  100. key := args[0].(string)
  101. value := args[1].(int64)
  102. if err := rds.Client.DecrBy(rds.Context, key, value).Err(); err != nil {
  103. logger.ErrorString("Redis", "Decrement", err.Error())
  104. return false
  105. }
  106. default:
  107. logger.ErrorString("Redis", "Decrement", "参数错误, 只能传入 1 或 2 个参数")
  108. return false
  109. }
  110. return true
  111. }
  112. // func (rds *RedisClient) Reconnect(ctx context.Context) {
  113. // for {
  114. // err := rds.Ping()
  115. // if err == nil {
  116. // logger.InfoString("Redis", "Ping", "Redis 连接正常")
  117. // return
  118. // }
  119. // logger.ErrorString("Redis", "Ping", "Redis 连接异常,正在重连...")
  120. // // 重新连接 Redis
  121. // rds.Client = redis.NewClient(&redis.Options{
  122. // Addr: rds.Client.Options().Addr,
  123. // Password: rds.Client.Options().Password,
  124. // DB: rds.Client.Options().DB,
  125. // })
  126. // select {
  127. // case <-ctx.Done():
  128. // logger.InfoString("Redis", "Reconnect", "Redis 重连已取消")
  129. // return
  130. // case <-time.After(5 * time.Second):
  131. // }
  132. // }
  133. // }
  134. // once 确保全局的 Redis 对象只实例一次
  135. var once sync.Once
  136. // Redis 全局 Redis, 使用 db 1
  137. var Redis *Client
  138. // ConnectRedis 连接 redis 数据库,设置全局 Redis 对象
  139. func ConnectRedis(address, username, password string, db int) {
  140. once.Do(func() {
  141. Redis = NewClient(address, username, password, db)
  142. })
  143. }
  144. func NewClient(address, username, password string, db int) *Client {
  145. rds := &Client{}
  146. rds.Context = context.Background()
  147. // 使用 redis 库里的 NewClient 初始化连接
  148. rds.Client = redis.NewClient(&redis.Options{
  149. Addr: address,
  150. Password: password,
  151. DB: db,
  152. })
  153. err := rds.Ping()
  154. logger.LogIf(err)
  155. // ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  156. // defer cancel()
  157. // rds.Reconnect(ctx)
  158. return rds
  159. }