如果一个可执行的redis的lua脚本无法返回值给客户端(java应用程序),那么这个事务是否回滚?

xv8emn3q  于 7个月前  发布在  Redis
关注(0)|答案(3)|浏览(144)

这是我的Lua脚本。

local field = ARGV[1]
local amount = ARGV[2]

local newAmount = redis.call("HINCRBYFLOAT", key, field, amount)
return newAmount

字符串
我在java应用程序中有一个lua脚本,我担心的是如果这个脚本没有返回“newAmount”,那么脚本的事务是否会回滚?
我的期望是回滚操作应该发生。

osh3o9ms

osh3o9ms1#

在Redis中,Lua脚本是以原子方式执行的。这意味着要么整个脚本都成功执行,要么一个都没有执行。如果Lua脚本没有返回值,(例如,由于脚本中的错误或异常),事务将不会部分应用,Redis服务器将不会提交脚本所做的任何更改。您对回滚操作的预期是正确的。**
在您提供的Lua脚本中,如果在执行过程中出现错误,没有返回newBalance,Redis服务器会确保该事务不被应用,并且不会对Redis数据库中的数据进行任何更改。
这种原子行为是Redis脚本的基本特性,在Lua脚本中执行多步操作时,可以保证数据的一致性和完整性。如果脚本出错,Redis数据存储不会发生任何变化,数据库保持一致状态。

eivnm1vs

eivnm1vs2#

不可以,在Redis Lua脚本中没有自动回滚transactions。如果脚本稍后出现故障,执行的命令不会回滚。实际上,Redis中根本不存在回滚。
但是有discussions关于实现某种回滚特性。
“原子地”的重要definition
Redis保证脚本的原子执行。在执行脚本时,所有服务器活动在整个运行期间都被阻止。
这意味着Redis将整个脚本视为一个操作,没有其他操作中断它。
为了防止错误,你应该在使用之前对所有的输入参数进行彻底的验证。为了处理潜在的错误,你可以使用redis.pcall()而不是redis.call()。使用redis.pcall(),你可以处理Redis引发的运行时错误,因为redis.pcall()总是返回一个回复,而不会抛出一个运行时异常。这对创建你自己的回滚逻辑和记录错误很有帮助。
范例:

local function scriptNoRollback(keys)
    redis.call("INCR", keys[1])
    redis.call("INCR", keys[2])

    return "OK"
end

local function scriptRollback(keys)
    -- Store initial value.
    local initValueCounter1 = redis.call("GET", keys[1])

    redis.call("INCR", keys[1])
    local reply = redis.pcall("INCR", keys[2])
    if type(reply) == "table" and reply["err"] ~= nil then
        reply["err"] = "Oops, error!"
        -- Try to rollback data.
        redis.call("SET", keys[1], initValueCounter1)

        return reply
    end

    return "OK"
end

字符串
scriptNoRollback正常:

127.0.0.1:6379> MSET counter1 1 counter2 2
OK
127.0.0.1:6379> FCALL scriptNoRollback 2 counter1 counter2
"OK"
127.0.0.1:6379> MGET counter1 counter2
1) "2"
2) "3"


scriptNoRollback错误:

127.0.0.1:6379> MSET counter1 1 counter2 A
OK
127.0.0.1:6379> FCALL scriptNoRollback 2 counter1 counter2
(error) ERR value is not an integer or out of range script: scriptNoRollback, on @user_function:118.
127.0.0.1:6379> MGET counter1 counter2
1) "2"
2) "A"


counter1不会回滚到初始状态。
scriptRollback正常:

127.0.0.1:6379> MSET counter1 1 counter2 2
OK
127.0.0.1:6379> FCALL scriptRollback 2 counter1 counter2
"OK"
127.0.0.1:6379> MGET counter1 counter2
1) "2"
2) "3"


scriptRollback错误:

127.0.0.1:6379> MSET counter1 1 counter2 A
OK
127.0.0.1:6379> FCALL scriptRollback 2 counter1 counter2
(error) Oops, error!
127.0.0.1:6379> MGET counter1 counter2
1) "1"
2) "A"


counter1回滚到初始状态。

eoxn13cs

eoxn13cs3#

在Redis中,Lua脚本不支持关系数据库管理系统(RDBMS)中的传统事务。Redis没有内置支持具有回滚功能的多语句事务(如RDBMS系统中的ACID事务)。
您提供的Lua脚本是一个原子操作,这意味着它要么完全成功,要么完全失败。它不是传统数据库意义上的事务,并且它没有失败时回滚的概念。
在Lua脚本中,如果发生错误(例如,由于参数无效或Redis服务器问题),脚本不会返回值,Java应用程序也不会收到响应。但是,它不会触发以前的Redis操作回滚。
如果你在Redis中需要类似transaction的行为,可以使用Redis内置的MULTI/EXEC transaction机制。你可以使用MULTI将多个命令排队,然后使用EXEC原子地执行它们。如果任何一个命令失败,整个transaction都会回滚。但是Lua脚本本身并不参与这种transaction机制。
总而言之,你的Lua脚本并没有提供类似transaction-like的回滚行为。如果你想确保Redis中的transactions,你应该使用MULTI/EXEC机制,而不是仅仅依靠Lua脚本。

相关问题