- golang系列(一)在Beego中存取Redis
- golang系列(二)基于Redis的分布式锁
- golang系列(三)在golang中使用kafka
- golang系列(四)在golang中使用gorm
- golang系列(五)常见的陷阱和错误
package redis_lok
import (
"fmt"
"github.com/astaxie/beego"
"github.com/gomodule/redigo/redis"
"riskcontrol/logger"
"time"
)
const (
default_timeout = 60
default_redis_pool_max_idle = 10
default_redis_pool_max_active = 20
)
var redisClient *redis.Pool
type Lock struct {
resource string
token string
timeout int
}
func init() {
redisHost := beego.AppConfig.String("Redis::Address")
dataBase,err := beego.AppConfig.Int("Redis::DataBase")
if err != nil{
logger.Logger.Error("redis database config error",err)
panic("redis database config error")
}
password := beego.AppConfig.String("Redis::Password")
// 建立连接池
redisClient = &redis.Pool{
MaxIdle: default_redis_pool_max_idle,
MaxActive: default_redis_pool_max_active,
IdleTimeout: default_timeout * time.Second,
Wait: true,
Dial: func() (redis.Conn, error) {
con, err := redis.Dial("tcp", redisHost,
redis.DialPassword(password),
redis.DialDatabase(dataBase),
redis.DialConnectTimeout(default_timeout*time.Second),
redis.DialReadTimeout(default_timeout*time.Second),
redis.DialWriteTimeout(default_timeout*time.Second))
if err != nil {
return nil, err
}
return con, nil
},
}
}
func (lock *Lock) tryLock() (ok bool, err error) {
_, err = redis.String(redisClient.Get().Do("SET", lock.key(), lock.token, "EX", int(lock.timeout), "NX"))
if err == redis.ErrNil {
// The lock was not successful, it already exists.
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func (lock *Lock) UnlockDeferDefault() (err error) {
time.Sleep(time.Duration(default_timeout) * time.Second)
_, err = redisClient.Get().Do("del", lock.key())
return
}
func (lock *Lock) Unlock() (err error) {
_, err = redisClient.Get().Do("del", lock.key())
return
}
func (lock *Lock) key() string {
return fmt.Sprintf("riskcontrol:redislock:%s", lock.resource)
}
func (lock *Lock) AddTimeout(ex_time int64) (ok bool, err error) {
ttl_time, err := redis.Int64(redisClient.Get().Do("TTL", lock.key()))
fmt.Println(ttl_time)
if err != nil {
logger.Logger.Error("redis get failed:", err)
}
if ttl_time > 0 {
fmt.Println(11)
_, err := redis.String(redisClient.Get().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(resource string, token string) (lock *Lock, ok bool, err error) {
return TryLockWithTimeout(resource, token, default_timeout)
}
func TryLockWithTimeout( resource string, token string, timeout int) (lock *Lock, ok bool, err error) {
lock = &Lock{resource, token, timeout}
ok, err = lock.tryLock()
if !ok || err != nil {
lock = nil
}
return
}
func demo() {
logger.Logger.Info("start")
lock, ok, err := TryLock( "test_key", "test_value")
if err != nil {
logger.Logger.Error("Error while attempting lock")
}
if !ok {
logger.Logger.Error("Lock failed")
}
defer lock.UnlockDeferDefault()
}