为了保证多条命令组合的原子性,Redis提供了简单的事务功能以及集成Lua脚本来解决这个问题。
Redis提供了简单的事务功能,将一组需要一起执行的命令放在multi和exec两个命令之间。multi命令代表事务开始,exec命令代表事务结束,它们之间的命令是原子顺序执行的。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd user:a:follow user:b
QUEUED
127.0.0.1:6379> sadd user:b:fans user:a
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
127.0.0.1:6379>
可以看到,sadd命令此时返回的结果是QUEUED,代表命令并没有真正执行,而是暂时保存在redis中,如果此时另一个客户端在exec之前执行sismember user:a:follow user:b 返回的结果应该是0;当执行exec之后,这两个命令才算完成执行。
如果要停止事务的执行,可以使用discard命令代替exec命令即可。
如果事务中出现命令错误,Redis的处理机制也不尽相同
1、命令错误:例如将set错写成sett,属于语法错误,会造成整个事务无法执行。
2、运行时错误:如用户b在添加粉丝列表时,误把sadd命令写成了zadd命令,这种就是运行时命令错误,因为语法正确。
127.0.0.1:6379> multi
OK
127.0.0.1:6379> sadd sadd user:a:follow user:b
QUEUED
127.0.0.1:6379> zadd user:b:fans 1 user:a
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379>
可以看到,Redis并不支持回滚功能,第一个命令已经执行完毕,开发人员需要自己修复这类问题 。
乐观锁
有些应用场景需要在事务之前,确保事务中的key没有被其他客户端修改过,才执行事务,否则不执行(类似乐观锁),Redis提供了watch命令来解决这里问题
//客户端一
127.0.0.1:6379> set testvalue leguan
OK
127.0.0.1:6379> get testvalue
"leguan"
127.0.0.1:6379> watch testvalue
OK
//客户端二
127.0.0.1:6379> append testvalue haha
(integer) 10
127.0.0.1:6379> get testvalue
"leguanhaha"
127.0.0.1:6379>
//客户端一
127.0.0.1:6379> multi
OK
127.0.0.1:6379> append testvalue hehe
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get testvalue
"leguanhaha"
127.0.0.1:6379>
可以看出,当客户端一在multi之前执行了watch命令后,客户端2对key进行了修改,当客户端1再进行修改key值时,exec结果为nil,即事务没有执行。
之所以说Redis提供了简单的事务,是因为它不支持事务的回滚特效,同时无法实现命令的逻辑关系计算。
Lua用法简述
Lua语言
1、Lua数据类型及逻辑处理
Lua语言提供了几种数据结构
booleans(布尔)
numbers(数值)
strings(字符串)
tables(表格)
1)定义字符串: local strings val="world"
其中,local代表val是一个局部变量,如果没有local代表是全局变量。print函数可以打印出变量的值,“--”是Lua语言的注释
--结果为“world”
print(hello)
2)数组
在Lua中,如果要使用类似数组的功能,可以用tables类型,下面代码定义了一个tables类型的变量myArray,但和大多数编程语言不同的是,Lua的数组下标从1开始计算。
local tables myArray = {"redis","jedis",true,88.0}
--输出结果:true
print(myArray[3])
如果想遍历这个数组,可以使用for或者while,
a) for
关键字for以end为结束符
local int sum=0
for i=1,100
do
sum = sum + 1
end
--输出结果为5050
print(sum)
要遍历myArray,首先需要知道tables的长度,只需要在变量前加一个#号即可。
for i=1,#myArray
do
print(myArray[i])
end
除此之外,Lua还提供了内置函数ipairs,使用for index,value ipairs(tables)可以遍历所有的索引下标和值:
for index,value in ipairs(myArray)
do
print(index)
print(value)
end
b)while
下面代码同样会计算1到100的和,只不过使用的是while循环,while循环同样以end作为结束符
local int sum=9
local int i = 0
while i <= 100
do
sum = sum + i
i = i + 1
end
--输出结果为5050
print(sum)
c) if else
要确定数组中是否包含了jedis,有则打印true,注意if以end结尾,if后紧跟then
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
3)哈希
1、如果要使用类似哈希的功能,同样可以使用tables类型,例如下面tables,每个元素包含了key和value,其中strings1 .. strings2是将两个字符串进行连接
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
2、函数定义
在Lua中,函数以function开头,以end结尾,funcName是函数名,中间部分是函数体
function funcName()
...
end
contact 函数将两个字符串拼接
function contact (str1,str2)
return str1 .. str2
end
-- "hello world"
print(contact("hello","world"))