使用SETNX命令(SET if Not eXists)
SETNX key value
将 key 的值设为 value,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。
设置成功,返回 1 。
设置失败,返回 0 。
为防止获取锁之后,忘记删除,成功后再设置一个过期时间
以上就是利用 redis 实现分布式锁的原理
代码package main
import (
"fmt"
"github.com/gomodule/redigo/redis"
"log"
"time"
)
type lock struct {
resource string
token string
conn redis.Conn
timeout int
}
func (lock *Lock) tryLock() (ok bool, err error) {
_, err = redis.String(lock.conn. Do ("SET", lock.key(), lock.token, "EX", int(lock.timeout), "NX"))
if err == redis.Err nil {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func (lock *Lock) Unlock () (err error) {
_, err = lock.conn.Do("del", lock.key())
return
}
func (lock *Lock) key() string {
return fmt.Sprintf("redislock:%s", lock.resource)
}
func (lock *Lock) AddTimeout(ex_time int64) (ok bool, err error) {
ttl_time, err := redis.Int64(lock.conn.Do("TTL", lock.key()))
fmt.Println(ttl_time)
if err != nil {
log.Fatal(err)
}
if ttl_time > 0 {
fmt.Println(11)
_, err := redis.String(lock.conn.Do("SET", lock.key(), lock.token, "EX", int(ttl_time+ex_time)))
if err == redis.ErrNil {
return false, nil
}
if err != nil {
return false, err
}
}
return false, nil
}
func TryLock(conn redis.Conn, resource string, token string, DefaultTimeout int) (lock *Lock, ok bool, err error) {
return TryLockWithTimeout(conn, resource, token, DefaultTimeout)
}
func TryLockWithTimeout(conn redis.Conn, resource string, token string, timeout int) (lock *Lock, ok bool, err error) {
lock = &Lock{resource: resource, token: token, conn: conn, timeout: timeout}
ok, err = lock.tryLock()
if !ok || err != nil {
lock = nil
}
return
}
func main() {
fmt.Println("start")
DefaultTimeout := 10
conn, err := redis.Dial("tcp", " localhost :6379")
if err != nil {
log.Fatal(err)
}
lock, ok, err := TryLock(conn, "anakin.sun", "token", int(DefaultTimeout))
if err != nil {
log.Fatal("error lock")
}
if !ok {
log.Fatal("lock fail")
}
lock.AddTimeout(100)
time.Sleep(time.Duration(DefaultTimeout) * time.Second)
fmt.Println("end")
defer lock.Unlock()
}