12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- package lockx
- import (
- "context"
- "github.com/zeromicro/go-zero/core/stores/redis"
- "time"
- )
- type DistributedLock struct {
- client *redis.Redis
- key string
- seconds int
- }
- func NewDistributedLock(client *redis.Redis, key string, seconds int) *DistributedLock {
- return &DistributedLock{
- client: client,
- key: key,
- seconds: seconds,
- }
- }
- // Lock 尝试获取分布式锁
- func (dl *DistributedLock) Lock() (bool, error) {
- if ok, err := dl.client.SetnxEx(dl.key, "1", dl.seconds); err != nil {
- return false, err
- } else if ok {
- return true, nil
- }
- return false, nil
- }
- // WaitLock 尝试获取分布式锁,获取不到等待
- func (dl *DistributedLock) WaitLock(ctx context.Context) error {
- for {
- select {
- case <-ctx.Done():
- // 如果Context被取消,则直接返回错误
- return ctx.Err()
- default:
- // 尝试获取锁
- result, err := dl.client.SetnxEx(dl.key, "1", dl.seconds)
- if err != nil {
- return err
- }
- if result {
- // 获取到锁,直接返回
- return nil
- }
- // 等待一段时间后重试
- time.Sleep(time.Millisecond * 50)
- }
- }
- }
- // Unlock 释放分布式锁
- func (dl *DistributedLock) Unlock() error {
- // 使用 Lua 脚本来保证原子性地删除锁(避免误删其他客户端的锁)
- luaScript := `
- if redis.call("get", KEYS[1]) == ARGV[1] then
- return redis.call("del", KEYS[1])
- else
- return 0
- end
- `
- _, err := dl.client.Eval(luaScript, []string{dl.key}, "1")
- return err
- }
|