代码
获得锁 释放锁
分布式锁可用必须满足一下四个条件
- 互斥性 在任意时刻 只有一个客户端能获取到锁
- 不会发生死锁 即使有一个客户端 在持有锁的期间奔溃而没有主动解锁, 也能保证后续客户端能解锁
- 具有容错性 只要大部分的redis 节点正常运行, 客户端就可以加锁和解锁
- 解锁加锁同一个客户端。 加锁和解锁必须是同一个客户端,客户端不能把别人加的锁给解除了。
package main
import (
"fmt"
"github.com/gomodule/redigo/redis"
"time"
)
// https://www.w3cschool.cn/redis/redis-yj3f2p0c.html
// redis 分布式锁实现
func init() {
initRedis()
}
var redisPool *redis.Pool
func initRedis() {
redisPool = &redis.Pool{
MaxIdle: 10,
MaxActive: 10,
IdleTimeout: 5 * time.Second,
Dial: func() (conn redis.Conn, e error) {
conn, err := redis.Dial("tcp", "127.0.1.1:6379")
if err != nil {
return nil, err
}
conn.Do("select", 0)
return conn, err
},
}
}
const LockName = "LockName"
const StringSetIfNotExist = "NX"
const StringSetWithExpireTime = "EX"
func getLock(id string) bool {
// 获得锁
// 一个命令原子操作 为了防止执行了nx 之后程序突然奔溃 则就会无法设置过期时间发生死锁
conn := redisPool.Get()
defer conn.Close()
_, err := redis.String(conn.Do("set", LockName, id, StringSetIfNotExist, StringSetWithExpireTime, 10))
if err == nil {
return true
}
return false
}
const luaScript = `
if redis.call('get', KEYS[1])==ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
`
func releaseDistributedLock(id string) bool {
// 释放分布式锁
// 也必须是原子操作 借助于lua 脚本实现
// 谁 上锁谁解锁
conn := redisPool.Get()
defer conn.Close()
lua := redis.NewScript(1, luaScript) // 定义参数的个数
_, err := redis.Int(lua.Do(conn, LockName, id)) // 上面定义几个参数conn 后面几个都是参数, 参数的后面就是值 按照顺序
if err == nil {
return true
}
return false
}
func main() {
theId := "yang"
flag := getLock(theId)
fmt.Println(flag)
releaseFlag := releaseDistributedLock(theId)
fmt.Println("releaseFlag: ", releaseFlag)
}