05-Redis 原子性和Lua

一、原子性

  • 原子性是指不可打断的一个完整操作。redis中单个命令是原子的,但是如果期望多个命令组合成一个原子操作,就不行
    了,此时需要借助Lua脚本来实现原子性、

  • Redis中的弱事务。redis的简单事务,将一组需要一起执行的命令放到multi和exec两个命令之间,其中multi代表事务开始,
    exec代表事务结束,不支持事物回滚,不能提供完整的事物特性,使用较少,涉及到的指令如下。

multi、watch、discard、exec

二、Lua

  • Lua是一个小巧的脚本语言,由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。
    一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。Lua内的代码可以保证原子性,要么全部成功,要么全部失败。
  • 在redis中使用Lua脚本的好处:
1.减少网络开销
2.原子操作
3.复用性  

2.1 Lua脚本示例

  • 如下脚本就是简单的保存address=shenzhen这个键值对,保存成功就返回success,反之返回fail
if redis.call('set',"address","shenzhen") ~= "shenzhen" then
	return "success";
else
	return "fail";
end
  • 使用./redis-cli --eval ./01.lua 执行后发现数据库中保存键值对成功

  • 下面是一个传参数的lua脚本的调用方式

if redis.call('set',KEYS[1],KEYS[2]) ~= KEYS[1] then
	return "success";
else
	return "fail";
end
  • 使用./redis-cli --eval ./02.lua hobby basketball 执行后数据库中保存键值对hobby=basketball成功。
    其实传参方式很简单,命令后面跟着参数,脚本里面使用KEYS[n]来接受对应的参数,n>0

2.2 redis-cli使用Lua脚本

  • redis客户端执行无参lua脚本:./redis-cli -a 123456 --eval ./01.lua
  • redis客户端执行有参lua脚本:./redis-cli -a 123456 --eval ./01.lua param1 param2 param3 …

2.3 jedis使用Lua脚本

image

  • Redis代码调用Lua脚本使用eval方法,我们可以看到jedis中有很多重载方法,可以使用字符串和byte数组形式表示Lua和参数,可以批量传参。
public class MyLua {

    public static final String REDIS_HOST = "127.0.0.1";
    public static final String REDIS_PASSWORD = "Intellifusion@20190108";
    public static final int REDIS_PORT = 6379;
    public static Jedis jedis = new Jedis(REDIS_HOST);

//    static {
//        jedis.auth(REDIS_PASSWORD);
//    }


    public static void main(String[] args) throws InterruptedException, IOException {
        byte[] lua = getContent("./02.lua");
        //key的字节数组集合
        List<byte[]> keyList = new ArrayList<>();
        keyList.add("hobby".getBytes());
        //值的字节数组集合
        List<byte[]> valList = new ArrayList<>();
        keyList.add("code".getBytes());
        jedis.eval(lua, keyList, valList);
    }

    //读取文件并以byte数组形式返回
    public static byte[] getContent(String filePath) throws IOException {
        File file = new File(filePath);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        FileInputStream fi = new FileInputStream(file);
        byte[] buffer = new byte[(int) fileSize];
        int offset = 0;
        int numRead = 0;
        while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
            offset += numRead;
        }
        // 确保所有数据均被读取
        if (offset != buffer.length) {
            throw new IOException("Could not completely read file " + file.getName());
        }
        fi.close();
        return buffer;
    }
}
  • 执行后redis中hobby对应的值就被改变了

三、参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值