Skip to content

Redis

Redis là một cơ sở dữ liệu lưu trữ cặp khóa-giá trị (Key-Value) mã nguồn mở, được viết bằng ngôn ngữ ANSI C, tuân thủ giao thức BSD, hỗ trợ mạng, có thể dựa trên bộ nhớ, phân tán, và có tùy chọn lưu trữ bền vững. Redis cung cấp API cho nhiều ngôn ngữ, có thể được sử dụng như một cơ sở dữ liệu NoSQL, cũng như một bộ nhớ cache tốc độ cao, và hỗ trợ hàng đợi tin nhắn đơn giản.

Bài viết này chỉ giải thích cách sử dụng trình điều khiển Go để thao tác cơ sở dữ liệu Redis, không giải thích gì thêm về bản thân Redis.

Tài liệu chính thức: Golang Redis client (uptrace.dev)

Kho lưu trữ chính thức: go-redis/redis: Type-safe Redis client for Golang (github.com)

Cài đặt

Có rất nhiều trình điều khiển cho Redis, bài viết này sử dụng github.com/go-redis/redis.

Nếu phiên bản Redis bạn sử dụng là 6

go get github.com/go-redis/redis/v8

Nếu phiên bản Redis bạn sử dụng là 7

go get github.com/go-redis/redis/v9

Bắt đầu nhanh

go
import (
   "fmt"
   "log"
   "testing"

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

func TestQuickStart(t *testing.T) {
   // Tạo máy khách kết nối Redis
   redisClient := redis.NewClient(&redis.Options{
      Addr:     "192.168.48.134:6379",
      Password: "123456",
      DB:       0, // Sử dụng DB mặc định
   })

   // Đặt cặp khóa-giá trị, 0 là không bao giờ hết hạn
   redisClient.Set("hello", "world", 0)

   // Đọc giá trị
   result, err := redisClient.Get("hello").Result()
   if err == redis.Nil {
      fmt.Println("ket not exist")
   } else if err != nil {
      log.Panic(err)
   }
   fmt.Println(result)
}

Cấu hình kết nối

go
type Options struct {
  // Loại mạng tcp hoặc unix.
  // Mặc định là tcp.
  Network string
  // Địa chỉ redis, định dạng host:port
  Addr string

    // Dialer tạo một kết nối mạng mới và có ưu tiên cao hơn các tùy chọn Network và Addr
  // Network and Addr options.
  Dialer func() (net.Conn, error)

  // Hàm này sẽ được gọi khi tạo một kết nối redis mới
  OnConnect func(*Conn) error

  // Mật khẩu redis, có thể để trống nếu redis server không đặt
  Password string

  // Cơ sở dữ liệu redis, bắt đầu từ 0, mặc định là 0, có thể không cần đặt
  DB int

  // Số lần thử lại tối đa khi thao tác redis thất bại, mặc định 0.
  MaxRetries int

  // Khoảng thời gian thử lại tối thiểu.
  // Mặc định là 8ms ; -1 biểu thị tắt.
  MinRetryBackoff time.Duration

  // Khoảng thời gian thử lại tối đa
  // Mặc định là 512ms; -1 biểu thị tắt.
  MaxRetryBackoff time.Duration

  // Thời gian chờ kết nối redis mới.
  // Mặc định là 5 giây.
  DialTimeout time.Duration

  // Thời gian chờ đọc socket
  // Mặc định 3 giây.
  ReadTimeout time.Duration

  // Thời gian chờ ghi socket
  WriteTimeout time.Duration

  // Số kết nối tối đa trong nhóm kết nối redis.
  // Kích thước nhóm kết nối mặc định bằng số cpu * 10
  PoolSize int

  // Số kết nối nhàn rỗi tối thiểu trong nhóm kết nối redis.
  MinIdleConns int

  // Thời gian tồn tại tối đa của kết nối redis, mặc định không đóng các kết nối lỗi thời.
  MaxConnAge time.Duration

  // Khi bạn lấy một kết nối từ nhóm kết nối redis, nhóm kết nối sẽ chờ kết nối này được lấy ra trong bao lâu.
  // Mặc định là chờ ReadTimeout + 1 giây.
  PoolTimeout time.Duration

  // Nhóm kết nối redis sẽ đóng một kết nối nhàn rỗi sau bao lâu.
  // Mặc định là 5 phút. -1 biểu thị tắt tùy chọn này
  IdleTimeout time.Duration

  // Kiểm tra bao lâu một lần, kết nối nhàn rỗi
  // Mặc định là 1 phút. -1 biểu thị tắt kiểm tra kết nối nhàn rỗi
  IdleCheckFrequency time.Duration

  // Cài đặt chỉ đọc, nếu đặt thành true, trên phiên bản nút hiện tại, redis chỉ có thể truy vấn cache không thể cập nhật.
  readOnly bool

    // Cấu hình TLS
  TLSConfig *tls.Config
}

Thiết lập kết nối

go
// Tạo máy khách kết nối Redis
redisClient := redis.NewClient(&redis.Options{
    Addr:     "192.168.48.134:6379",
    Password: "123456",
    DB:       0, // Sử dụng DB mặc định
})

Đóng kết nối

Trình điều khiển duy trì một nhóm kết nối nội bộ, không cần đóng kết nối sau mỗi thao tác.

go
defer redisClient.Close()

Trình điều khiển Redis này đã đóng gói gần như tất cả các thao tác, lệnh Redis và tên phương thức tương ứng một-một, về cơ bản chỉ cần biết cách sử dụng lệnh Redis thì phương thức tương ứng của trình điều khiển cũng gần như biết.

Lệnh Redis: redis 命令手册

Thao tác cơ bản

Xóa khóa

go
redisClient.Set("name", "jack", 0)
fmt.Println(redisClient.Del("name").Result())

Thời gian hết hạn

go
redisClient.Set("name", "jack", 0)
// Đặt thời gian hết hạn
redisClient.Expire("name", time.Second*2)
fmt.Println(redisClient.Get("name").Val())
time.Sleep(time.Second * 3)
fmt.Println(redisClient.Get("name").Val())

Hủy thời gian hết hạn

go
redisClient.Set("name", "jack", 2)
// Hủy thời gian hết hạn
redisClient.Persist("name")
time.Sleep(time.Second * 2)
fmt.Println(redisClient.Get("name"))

Truy vấn thời gian hết hạn

go
fmt.Println(redisClient.TTL("name"))
fmt.Println(redisClient.PTTL("name"))

Đổi tên

go
redisClient.Rename("name", "newName")

Truy vấn loại

go
redisClient.Type("name")

Quét

go
fmt.Println(redisClient.Scan(0, "", 4))

Chuỗi

Lưu trữ đơn giản

go
redisClient.Set("token", "abcefghijklmn", 0)
fmt.Println(redisClient.Get("token").Val())

Lưu trữ hàng loạt

go
redisClient.MSet("cookie", "12345", "token", "abcefg")
fmt.Println(redisClient.MGet("cookie", "token").Val())

Tăng giảm số

go
redisClient.Set("age", "1", 0)
// Tự tăng
redisClient.Incr("age")
fmt.Println(redisClient.Get("age").Val())
// Tự giảm
redisClient.Decr("age")
fmt.Println(redisClient.Get("age").Val())

Bảng băm

Thao tác đọc ghi

go
// Đặt đơn
redisClient.HSet("map", "name", "jack")
// Đặt hàng loạt
redisClient.HMSet("map", map[string]interface{}{"a": "b", "c": "d", "e": "f"})
// Truy cập đơn
fmt.Println(redisClient.HGet("map", "a").Val())
// Truy cập hàng loạt
fmt.Println(redisClient.HMGet("map", "a", "b").Val())
// Lấy toàn bộ map
fmt.Println(redisClient.HGetAll("map").Val())

Đầu ra

b
[b <nil>]
map[a:b c:d e:f name:jack]

Xóa khóa

go
// Xóa một trường của map
redisClient.HDel("map", "a")

Kiểm tra khóa có tồn tại

go
// Kiểm tra trường có tồn tại
redisClient.HExists("map", "a")

Lấy tất cả các khóa

go
// Lấy tất cả các khóa của map
redisClient.HKeys("map")

Lấy độ dài bảng băm

go
// Lấy độ dài map
redisClient.HLen("map")

Duyệt qua các cặp khóa-giá trị của bảng băm

go
// Duyệt qua các cặp khóa-giá trị trong map
redisClient.HScan("map", 0, "", 1)

Danh sách

Sửa đổi phần tử

go
// Thêm bên trái
redisClient.LPush("list", "a", "b", "c", "d", "e")
// Thêm bên phải
redisClient.RPush("list", "g", "i", "a")
// Chèn giá trị trước giá trị tham chiếu
redisClient.LInsertBefore("list", "a", "aa")
// Chèn giá trị sau giá trị tham chiếu
redisClient.LInsertAfter("list", "a", "gg")
// Đặt giá trị của phần tử tại chỉ số được chỉ định
redisClient.LSet("list", 0, "head")

Truy cập độ dài

go
// Truy cập độ dài danh sách
redisClient.LLen("list")

Truy cập phần tử

go
// Lấy phần tử bên trái
redisClient.LPop("list")
// Lấy phần tử bên phải
redisClient.RPop("list")
// Truy cập phần tử tại chỉ số được chỉ định
redisClient.LIndex("list", 1)
// Truy cập các phần tử trong phạm vi được chỉ định
redisClient.LRange("list", 0, 1)

Xóa phần tử

go
// Xóa phần tử được chỉ định
redisClient.LRem("list", 0, "a")
// Xóa các phần tử trong phạm vi được chỉ định
redisClient.LTrim("list", 0, 1)
// Giữ các phần tử trong phạm vi được chỉ định
redisClient.LTrim("list", 0, 1)

Tập hợp

Thêm phần tử

go
// Thêm phần tử vào một tập hợp
redisClient.SAdd("set", "a", "b", "c")
redisClient.SAdd("set2", "c", "d", "e")

Truy cập phần tử tập hợp

go
// Lấy tất cả các thành viên trong tập hợp
redisClient.SMembers("set")
// Kiểm tra một phần tử có thuộc tập hợp này không
redisClient.SIsMember("set", "a")
// Trả về ngẫu nhiên count phần tử
redisClient.SRandMemberN("set", 1)
// Lấy số lượng phần tử của một tập hợp
redisClient.SCard("set")

Thao tác tập hợp

go
// Trả về hiệu của các tập hợp được chỉ định
redisClient.SDiff("set", "set2")
// Lưu hiệu của các tập hợp được chỉ định vào tập kết quả, trả về độ dài tập kết quả
redisClient.SDiffStore("store", "set", "se2")
// Trả về giao của các tập hợp được chỉ định
redisClient.SInter("set", "set2")
// Lưu giao của các tập hợp được chỉ định vào tập kết quả, trả về độ dài tập kết quả
redisClient.SInterStore("store", "set", "set2")
// Trả về hợp của các tập hợp được chỉ định
redisClient.SUnion("set", "set2")
// Lưu hợp của các tập hợp được chỉ định vào tập kết quả, trả về độ dài tập kết quả
redisClient.SUnionStore("store", "set", "store")

Xóa phần tử

go
// Lấy ra và xóa phần tử
redisClient.SPop("set")
// Lấy ra và xóa N phần tử
redisClient.SPopN("set", 2)

Di chuyển phần tử

go
// Di chuyển phần tử được chỉ định từ tập hợp nguồn đến tập hợp đích
redisClient.SMove("set", "set2", "a")

Xóa phần tử

go
// Xóa phần tử được chỉ định
redisClient.SRem("set", "a", "b")

Duyệt qua

go
// Duyệt qua tập hợp
redisClient.SScan("set", 0, "", 2)

Tập hợp có thứ tự

Thêm phần tử

go
// Thêm phần tử vào tập hợp có thứ tự
redisClient.ZAdd("ss", redis.Z{
   Score:  1,
   Member: "a",
}, redis.Z{
   Score:  2,
   Member: "b",
})

Xếp hạng phần tử

go
// Trả về xếp hạng của phần tử trong tập hợp có thứ tự, sắp xếp từ thấp đến cao
redisClient.ZRank("ss", "1")
// Trả về xếp hạng của phần tử trong tập hợp có thứ tự, sắp xếp từ cao đến thấp
redisClient.ZRevRank("ss", "1")

Truy cập phần tử

go
// Trả về số lượng thành viên giữa min và max
redisClient.ZCount("ss", "1", "2")

// Trả về trọng số của phần tử
redisClient.ZScore("ss", "a")

// Trả về các phần tử trong khoảng được chỉ định
redisClient.ZRange("ss", 1, 2)
// Trả về tất cả các thành viên giữa min và max
redisClient.ZRangeByScore("ss", redis.ZRangeBy{
   Min:    "1",
   Max:    "2",
   Offset: 0,
   Count:  1,
})

Sửa đổi trọng số

go
// Tăng trọng số tương ứng cho một phần tử
redisClient.ZIncr("ss", redis.Z{
   Score:  2,
   Member: "b",
})

Xóa phần tử

go
// Xóa phần tử được chỉ định
redisClient.ZRem("ss", "a")
// Xóa các phần tử trong khoảng xếp hạng được chỉ định
redisClient.ZRemRangeByRank("ss", 1, 2)
// Xóa các phần tử có trọng số trong khoảng min và max
redisClient.ZRemRangeByScore("ss", "1", "2")

Kịch bản

go
// Tải kịch bản, trả về giá trị sha
redisClient.ScriptLoad("return 0")
// Thực thi kịch bản theo giá trị sha
redisClient.EvalSha("sha", []string{}, "")
// Thực thi kịch bản trực tiếp
redisClient.Eval("return 0", []string{}, "")
// Xóa bộ nhớ cache kịch bản
redisClient.ScriptFlush()
// Kết thúc kịch bản đang chạy hiện tại
redisClient.ScriptKill()
// Kiểm tra xem kịch bản của giá trị băm tương ứng có tồn tại không
redisClient.ScriptExists("")

Phát hành đăng ký

go
// Gửi tin nhắn đến kênh được chỉ định
redisClient.Publish("channel", "message")
// Đăng ký kênh được chỉ định
redisClient.Subscribe("channel")
// Xem trạng thái đăng ký
redisClient.PubSubNumSub("channel")

Golang by www.golangdev.cn edit