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/v8Nếu phiên bản Redis bạn sử dụng là 7
go get github.com/go-redis/redis/v9Bắt đầu nhanh
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
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
// 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.
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
redisClient.Set("name", "jack", 0)
fmt.Println(redisClient.Del("name").Result())Thời gian hết hạn
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
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
fmt.Println(redisClient.TTL("name"))
fmt.Println(redisClient.PTTL("name"))Đổi tên
redisClient.Rename("name", "newName")Truy vấn loại
redisClient.Type("name")Quét
fmt.Println(redisClient.Scan(0, "", 4))Chuỗi
Lưu trữ đơn giản
redisClient.Set("token", "abcefghijklmn", 0)
fmt.Println(redisClient.Get("token").Val())Lưu trữ hàng loạt
redisClient.MSet("cookie", "12345", "token", "abcefg")
fmt.Println(redisClient.MGet("cookie", "token").Val())Tăng giảm số
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
// Đặ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
// Xóa một trường của map
redisClient.HDel("map", "a")Kiểm tra khóa có tồn tại
// Kiểm tra trường có tồn tại
redisClient.HExists("map", "a")Lấy tất cả các khóa
// Lấy tất cả các khóa của map
redisClient.HKeys("map")Lấy độ dài bảng băm
// 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
// 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ử
// 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
// Truy cập độ dài danh sách
redisClient.LLen("list")Truy cập phần tử
// 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ử
// 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ử
// 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
// 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
// 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ử
// 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ử
// 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ử
// Xóa phần tử được chỉ định
redisClient.SRem("set", "a", "b")Duyệt qua
// Duyệt qua tập hợp
redisClient.SScan("set", 0, "", 2)Tập hợp có thứ tự
Thêm phần tử
// 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ử
// 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ử
// 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ố
// 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ử
// 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
// 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ý
// 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")