事务
所谓事务(Transaction) ,是指作为单个逻辑工作单元执行的一系列操作
ACID回顾
- Atomicity(原子性): 构成事务的的所有操作必须是一个逻辑单元,要么全部执行,要么全部不 执行。
- Consistency(一致性): 数据库在事务执行前后状态都必须是稳定的或者是一致的。
- Isolation(隔离性): 事务之间不会相互影响。
- Durability(持久性): 事务执行成功后必须全部写入磁盘。
Redis事务
Redis 事务的本质是一组命令的集合
- Redis的事务是通过multi、exec、discard和watch这四个命令来完成的。
- Redis的单个命令都是原子性的,所以这里需要确保事务性的对象是命令集合。
- Redis将命令集合序列化并确保处于同一事务的命令集合连续且不被打断的执行 、
- Redis不能保障失败回滚
注意事项 注意!redis的事务远远弱于mysql,严格意义上,它不能叫做事务,只是一个命令打包的批处理,不能 保障失败回滚。 这是官方文档的原话:
It's important to note that even when a command fails, all the other commands in the
queue are processed – Redis will not stop the processing of commands.
原理分析
- 调用multi指令后,redis其实是开启了一个命令队列,后续的命令被提交到队列(还没有执行)
- 期间出现问题了(比如down机),终止操作,队列清空
- 到exec命令后,批量提交,事务完成
操作演示
192.168.139.187:0>multi
"OK"
192.168.139.187:0>set k1 v1
"QUEUED"
192.168.139.187:0>get k1
"QUEUED"
192.168.139.187:0>exec
1) "OK"
2) "OK"
3) "OK"
4) "v1"
5) "OK"
192.168.139.187:0>
关于回滚
注意!回滚要看两种情况:
- 直接语法错误,redis完全无法执行,Redis 2.6.5之前的版本不会回滚,之后版本整个事务回滚
- 执行期的错误,redis不会回滚,其他正确的指令会照样执行
验证:错误的命令,导致回滚(版本:6.2.6)
192.168.139.187:0>set a a
"OK"
192.168.139.187:0>get a
"a"
192.168.139.187:0>multi
"OK"
192.168.139.187:0>set a b
"QUEUED"
192.168.139.187:0>set a
"ERR wrong number of arguments for 'set' command"
192.168.139.187:0>exec
"EXECABORT Transaction discarded because of previous errors."
192.168.139.187:0>get a
"a"
验证:命令语法对,但是数据类型不对,执行期间才会被发现!
192.168.139.187:0>get a
"a"
192.168.139.187:0>multi
"OK"
192.168.139.187:0>set a b
"QUEUED"
192.168.139.187:0>lpush a 1
"QUEUED"
192.168.139.187:0>exec
1) "OK"
2) "OK"
3) "OK"
4) "WRONGTYPE Operation against a key holding the wrong kind of value"
5) "OK"
192.168.139.187:0>get a
"b"
Lua脚本
lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程 序中,从而为应用程序提供灵活的扩展和定制功能。
Lua应用场景:
- 游戏开发
- 独立应用脚本
- Web应用脚本
- 扩展和数据库插件
- Nginx + lua开发高性能web应用,限流、防止Sql注入…
Redis使用lua脚本
版本:自2.6.0起可用,通过内置的lua编译/解释器,可以使用EVAL命令对lua脚本进行求值。
时间复杂度:取决于执行的脚本。
使用Lua脚本的好处:
- 减少网络开销。可以将多个请求通过脚本的形式一次发送,减少网络时延。
- 原子操作。redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。因此在编写脚本的
过程中无需担心会出现竞态条件,无需使用事务。 - 复用。客户端发送的脚本会永久存在redis中,这样,其他客户端可以复用这一脚本而不需要使用
代码完成相同的逻辑。 命令格式:
EVAL script numkeys key [key ...] arg [arg ...]
命令说明:
- script :参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数
- numkeys : 用于指定键名参数的个数。
- key [key …] ,是要操作的键,可以指定多个,在lua脚本中通过 KEYS[1] , KEYS[2] 获取
- arg [arg …] ,附加参数,在lua脚本中通过 ARGV[1] , ARGV[2] 获取。
实例:
192.168.139.187:0>eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 one two
1) "key1"
2) "key2"
3) "one"
4) "two"
lua脚本中调用Redis命令
- redis.call():
返回值就是redis命令执行的返回值 如果出错,则返回错误信息,不继续执行 - redis.pcall():
返回值就是redis命令执行的返回值 如果出错,则记录错误信息,继续执行 注意事项 在脚本中,使用return语句将返回值返回给客户端,如果没有return,则返回nil
192.168.139.187:0>eval "return redis.call('set',KEYS[1],ARGV[1])" 1 name 清风冷影
"OK"
|