redis编写lua脚本

由于redis并没有类似mysql或者mongo的乐观锁机制,并发控制成了一个棘手的问题
这块是可以用redis的watch来做,但是如果能实现乐观锁,那就非常方便了

redis使用lua的基础语法

1  
2  
3  
4  
5  
> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second  
1) "key1"  
2) "key2"  
3) "first"  
4) "second"  

—|—

lua可以调用的redis函数

1  
2  
redis.call()  
redis.pcall()  

—|—

简单例子

1  
2  
3  
4  
5  
6  
7  
8  
9  
local version = redis.call("INCR", KEYS[2])  
if version == 1 then  
    redis.call("EXPIRE", KEYS[2], ARGV[3])  
end;  
  
if tostring(version) ~= ARGV[2] then  
    return {-1, version}  
end;  
return redis.call("SET", KEYS[1], ARGV[1])  

—|—

运行方式:

1  
redis-cli EVAL "$(cat ./helloWorld.lua)" 3 mykey version1 expire 1 1 100  

—|—

redis并发控制

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
func (db *RedisDB) (key string, val interface{}, versionKey string, versionVal int, versionExpire int) (err error) {  
	if versionExpire == 0 {  
		versionExpire = 100  
	}  
	storeValue, err := db.getStoreValue(val)  
	if err != nil {  
		return  
	}  
  
	conn := db.Option.Pool.Get()  
	defer conn.Close()  
	if err = conn.Err(); err != nil {  
		return err  
	}  
  
	script := `  
local version = redis.call("INCR", KEYS[2])  
if version == 1 then  
    redis.call("EXPIRE", KEYS[2], ARGV[3])  
end;  
  
if tostring(version) ~= ARGV[2] then  
    return {-1, version}  
end;  
return redis.call("SET", KEYS[1], ARGV[1])  
`  
	getScript := redis.NewScript(3, script)  
	res, err := redis.String(getScript.Do(conn, key, versionKey, "expire", storeValue, versionVal, versionExpire))  
  
	if err != nil {  
		utils.Error(err)  
		return  
	}  
	if res == "-1" {  
		//err = ErrConflict  
	}redis  
	return  
}  

—|—

相关文档

Redis 命令参考 · lua 脚本

糖果

糖果
LUA教程

Lapis框架的常用处理方法

Lapis框架的常用处理方法 Continue reading

MoonScript实现选择排序

Published on February 26, 2017

MoonScript与Redis客户端

Published on January 19, 2017