go redigo执行lua脚本 实现原子操作

栏目: Lua · 发布时间: 6年前

内容简介:Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua可以在很多地方使用比如游戏开发、独立应用脚本、Web应用脚本、扩招和数据库插件等等。今天记录的是在redis中执行lua脚本实现原子操作。如果不是专业些lua脚本我们可以看下在redis中使用lua的场景很多,这次记录的使用场景是:开发需要用到redis记录一个有顺序的数据,但是又不能重复添加。所以准备先用一个set记录list存在的值用来判断是否重复(set

Lua

Lua 是一种轻量小巧的脚本语言,用标准 C语言 编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

Lua可以在很多地方使用比如游戏开发、独立应用脚本、Web应用脚本、扩招和数据库插件等等。今天记录的是在 redis 中执行 lua 脚本实现原子操作。如果不是专业些lua脚本我们可以看下 菜鸟联盟 的简单教程,已经够我们平时简单使用了。

使用场景

在redis中使用lua的场景很多,这次记录的使用场景是:开发需要用到redis记录一个有顺序的数据,但是又不能重复添加。所以准备先用一个set记录list存在的值用来判断是否重复(set在redis中是不允许重复的),再用list数据类型进行保存。但是如果分开执行这些语句在高并发的情况下可能会遇到问题,在某种情况下可能会加入重复数据。这个时候就可以用到lua脚本来原子的执行这两条语句。

代码

package main

import (
    "fmt"
    "time"
    "github.com/gomodule/redigo/redis"
)

const(
    SCRIPT_INCR = `
local num = redis.call('sismember', KEYS[1], ARGV[1])
if num > 0
then
    return -1
else
    redis.call('sadd',KEYS[1],ARGV[1])
    return redis.call('lpush',KEYS[2],ARGV[1])
end
`
)

func init()(){
    initRedis()
}

var redisCoon redis.Conn

//初始化redis连接,redis在本地 docker 中运行
func initRedis()(){
    redisClient := &redis.Pool{
        // 最大空闲链接
        MaxIdle: 10,
        // 最大激活链接
        MaxActive: 10,
        // 最大空闲链接等待时间
        IdleTimeout: 5 * time.Second,
        Dial: func() (redis.Conn, error) {
            rc, err := redis.Dial("tcp", "127.0.0.1:6379")
            if err != nil {
                return nil, err
            }
            rc.Do("SELECT", 0)
            fmt.Println("USE DB", 0)

            return rc, nil
        },
    }
    redisCoon = redisClient.Get()
}

func AddCode(id,code string)(){
    lua := redis.NewScript(2, SCRIPT_INCR)
    in,err :=redis.Int(lua.Do(redisCoon, "u:"+id, "u:set:"+id, code))
    fmt.Println(in,"--",err)
}

func main() {
    AddCode("1","60001")
    AddCode("1","60001")
    AddCode("1","60002")
}

//执行结果
//1 -- <nil>
//-1 -- <nil>
//2 -- <nil>
//redis查询结果
//127.0.0.1:6379> lrange u:set:1 0 -1
//1) "60002"
//2) "60001"
//127.0.0.1:6379> smembers u:1
//1) "60001"
//2) "60002"

go 中使用的是redigo的包来操作redis。redigo自带redis连接池可以方便的定义做大连接数,最大空闲数,最大空闲连接等和超时时间等。我们可以很方便控制这些参数也可以很方便的执行lua脚本。执行步骤如下:

  1. 第一步需要新建一个脚本对象,第一个参数为keycount,标志你的lua脚本参数中key的个数 第二个参数为脚本字符串
  2. 第二步 执行这个脚本,把定义时候的2个key传递过去,之后的参数为脚本中的ARGV
  3. 第三部 使用redis.Int 获取返回值,如果没有返回值直接使用Do即可

脚本接受一个set的key和一个list的key 先判断set是否存在保证没有重复。之后再去往list中添加,避免高并发中加入重复数据。如果已经存在则返回-1表示。如果没有则往set,list中都添加值。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python 3 the Hard Way

Learn Python 3 the Hard Way

Zed A. Shaw / Addison / 2017-7-7 / USD 30.74

You Will Learn Python 3! Zed Shaw has perfected the world’s best system for learning Python 3. Follow it and you will succeed—just like the millions of beginners Zed has taught to date! You bring t......一起来看看 《Learn Python 3 the Hard Way》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器