Redis之事务与Lua

1.  为什么使用事务与lua

    为了保证多条命令组合的原子性

2.  Redis事务

    1.  redis事务功能

        将一组需要一起执行的命令放到multi和exec两个命令之间

        multi代表事务开始

        exec代表事务结束

        他们之间的命令是原子顺序执行的

        discard代表中止事务

        例子:

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name yangjianbo
QUEUED
127.0.0.1:6379> exec
1) OK

在事务还没有提交前,其它客户端查看get name, 为空,直到提交以后,才显示对应的value。  

    2.  如果事务中的命令出现错误,Redis的处理机制也不尽相同

        1.  命令输入错误(语法错误)

            将命令写错

            例子:

127.0.0.1:6379> get b
"2"
127.0.0.1:6379> multi 
OK
127.0.0.1:6379> incr b 
QUEUED
127.0.0.1:6379> sett c
(error) ERR unknown command 'sett'
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get b
"2"
当命令出现语法错误的时候,提交事务的时候会有报错。事务内其他的命令执行也不会生效。

        2.  运行时错误

            将命令用错了,但不是语法错误,本来应该使用set,使用了mset        

            例子:

127.0.0.1:6379> get b
"2"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr b 
QUEUED
127.0.0.1:6379> mset c 1
QUEUED
127.0.0.1:6379> exec
1) (integer) 3
2) OK
127.0.0.1:6379> get b
"3"
将命令因为人为因素写错的例如:sadd写成了zadd ,redis认为使用没有问题,redis不支持回滚。

    3.  redis的watch命令

        1.  事务中watch命令演示时序

            

 

            当一些场景在事务执行之前,确保事务中的key没有被其它客户端修改过,才能执行事务,否则不执行。Redis提供了watch命令来解决这个问题。

         2.  例子:            

客户端1
127.0.0.1:6379> get name
"yangjianbo"
127.0.0.1:6379> watch name
OK
127.0.0.1:6379> multi
OK
客户端2
127.0.0.1:6379> append name yichangkun
(integer) 20
客户端1
127.0.0.1:6379> append name luoying
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get name
"yangjianboyichangkun"
因为客户端2在exec之前修改了name值,造成客户端1事务exec结果为nil。

3.  Lua用法简述  

    1.  数据类型

数据类型描述
nil 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。
boolean 包含两个值:false和true。
number 表示双精度类型的实浮点数
string 字符串由一对双引号或单引号来表示
function 由 C 或 Lua 编写的函数
userdata 表示任意存储在变量中的C数据结构
thread 表示执行的独立线路,用于执行协同程序
table Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。

        1.  字符串

[root@192 ~]# lua -i
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> local string a='yangjianbo'
> print(a)
yangjianbo         

        2.  数组

> local tables yunwei={"yangjianbo","yichangkun","luoying"}
> print (yunwei[3])
luoying           

    2.  逻辑处理

        1.  for

            1.  计算1到100的和

local int sum = 0
for i = 1, 100
do
sum = sum + i
end
-- 输出结果为5050
print(sum)

            2.  遍历某个数组

> for i=1,#yunwei
>> do 
>> print(yunwei[i])
>> end
yangjianbo
yichangkun
luoying

            3.  通过内置函数ipairs,遍历出所有的索引下标和值 

> for index,value in ipairs(yunwei)
>> do 
>> print(index)
>> print(value)
>> end
1
yangjianbo
2
yichangkun
3
luoying            

        2.  while

local int sum = 0
local int i = 0
while i <= 100
do
sum = sum +i
i = i + 1
end
--输出结果为5050
print(sum)  

        3.  if else

local tables myArray = {"redis", "jedis", true, 88.0}
for i = 1, #myArray
do
if myArray[i] == "jedis"
then
print("true")
break
else
--do nothing
end
end  

        4.  哈希

local tables user_1 = {age = 28, name = "tome"}
--user_1 age is 28
print("user_1 age is " .. user_1["age"])

遍历user_1,使用Lua的内置函数pairs

> for key,value in pairs(user_1)
>> do print(key .. value)
>> end
age28
nametome          

        5.  函数

function funcName()
...
end
contact函数将两个字符串拼接:
function contact(str1, str2)
return str1 .. str2
end
--"hello world"
print(contact("hello ", "world"))

4.  Redis与Lua

    1.  在Redis中使用Lua

        1.  eval

            1.  语法

                eval 脚本内容 key个数 key列表 参数列表

            2.  例子                

192.168.1.201:6379> eval "return  {KEYS[1],KEYS[2],KEYS[3],ARGV[1],ARGV[2],ARGV[3]}" 3 redis world name yang age 18
1) "redis"
2) "world"
3) "name"
4) "yang"
5) "age"
6) "18"

            3.  执行过程

                

        2.  redis-cli --eval

            与eval本质相同            

        3.  evalsha

            首先将Lua脚本加载到Redis服务端,得到该脚本的SHA1校验和,evalsha命令使用SHA1作为参数可以直接执行对应Lua脚本,避免每次发送Lua脚本的开销。这样客户端不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本功能得到了复用。

            

 

            1.  加载脚本

                redis-cli script load "$(cat 1.lua)"

                1.lua的内容:print("hello")  执行加载的时候,最好要进入到lua脚本所在的目录中                                

            2.  执行脚本

                EVALSHA a5e636d1097ffc88e9ed41027511f1fbe3fe2efd 1 yangjianbo name

     2.  Lua的Redis API

        Lua可以使用redis.call函数实现对redis的访问

redis.call("set", "hello", "world")
redis.call("get", "hello")
放在Redis的执行效果如下:
127.0.0.1:6379> eval 'return redis.call("get", KEYS[1])' 1 hello
"world

    3.  Lua脚本带来的好处

        1.  Lua脚本在redis中是原子执行的,执行过程中不会插入其他命令

        2.  Lua脚本可以实现复用的效果

        3.  Lua脚本可以将多条命令一次性打包,有小弟减少网络开销  

    4.  Redis如何管理lua脚本

        1.  加载脚本

            script load

        2.  判断sha1是否已经加载到redis内存中

            script exists a5e636d1097ffc88e9ed41027511f1fbe3fe2efd

        3.  清除redis内存已经加载的所有lua脚本

            script flush

        4.  杀掉lua脚本

            script kill

              当redis发生阻塞时,会有提示:需要执行script kill命令

              当redis发生写操作时,那么script kill将不会生效

             

        

                                  

    

      

posted @ 2022-02-18 13:18  奋斗史  阅读(418)  评论(0)    收藏  举报