Redis的分布式锁是通过利用Redis的单线程特性以及原子操作来实现的
Redis的SET命令具有原子性,这意味着只有一个客户端能够成功地设置该键,其他客户端将无法获得锁。如果SET命令成功,表示该客户端成功获得了锁。
Redis锁示例代码
package redis
import (
"fmt"
"github.com/go-redis/redis"
"log"
"strconv"
"sync"
"testing"
"time"
)
var client *redis.Client
var mutex sync.Mutex
// 初始化连接
func initClient() (err error) {
client = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // 没有密码,默认值
DB: 2, // 默认DB 0
})
_, err = client.Ping().Result()
return err
}
// 加锁
func Lock(key string) (bool, error) {
// 10秒之后,自动解锁,防止死锁
delayUnLockTime := 10 * time.Second
mutex.Lock()
defer mutex.Unlock()
bool, err := client.SetNX(key, `{"lock":1}`, delayUnLockTime).Result()
if err != nil {
return bool, err
}
return bool, err
}
// 解锁
func UnLock(key string, i int) (int64, error) {
nums, err := client.Del(key).Result()
if err != nil {
log.Println(err.Error())
return 0, err
}
fmt.Println(strconv.Itoa(i) + key + "解锁成功,删除key的成功:" + strconv.Itoa(int(nums)))
return nums, nil
}
func LockTest(key string, i int) {
result, err := Lock(key)
if err != nil {
fmt.Println(err)
return
}
if result {
fmt.Println(strconv.Itoa(i) + key + "锁定成功")
return
}
fmt.Println(strconv.Itoa(i) + key + "锁定失败")
}
func TestRedis(t *testing.T) {
err := initClient()
if err != nil {
fmt.Println(err)
return
}
LockTest("lock_key", 1)
go LockTest("lock_key", 2)
go LockTest("lock_key", 3)
time.Sleep(1 * time.Second)
go UnLock("lock_key", 1)
go UnLock("lock_key", 2)
go UnLock("lock_key", 3)
time.Sleep(10 * time.Second)
}