redis中实现事务有两种方法:
1.WATCH监视键的变动,然后MULTI开始事务,EXEC提交事务
WATCH key [key…]:监视一个或多个键,如果在事务执行之前被修改,则事务被打断。
MULTI:标记一个事务的开始。
EXEC:执行事务中的所有命令。
DISCARD:取消一个事务,放弃执行事务中的所有命令。
WACTH检测 key 的变动,若在事务执行中,key 变动则取消事务,在事
务开启前调用,乐观锁实现(cas),
若被取消则事务返回 nil 。
例如:
实现加倍操作
WATCH score:10001
val = GET score:10001
MULTI
SET score:10001 val*2
EXEC
缺点:乐观锁实现,所以失败需要重试,增加业务逻辑的复杂度,所以一般使用第二种方法。
2.使用lua脚本
lua 脚本实现原子性
redis 中加载了一个 lua 虚拟机;用来执行 redis lua 脚本,redislua 脚本的执行是原子性的,当某个脚本正在执行的时候,不会有其他命令或者脚本被执行。
lua 脚本当中的命令会直接修改数据状态,lua 脚本 mysql 存储区别:MySQL存储过程不具备事务性,所以也不具备原子性。
# 从文件中读取 lua脚本内容
cat test1.lua | redis-cli script load --pipe
# 加载 lua脚本字符串 生成 sha1
> script load 'local val = KEYS[1]; return val'
"b8059ba43af6ffe8bed3db65bac35d452f8115d8"
# 检查脚本缓存中,是否有该 sha1 散列值的lua脚本
> script exists
"b8059ba43af6ffe8bed3db65bac35d452f8115d8"
1) (integer) 1
# 清除所有脚本缓存
> script flush
OK
# 如果当前脚本运行时间过长(死循环),可以通过 script kill
杀死当前运行的脚本
> script kill
(error) NOTBUSY No scripts in execution right
now.
执行脚本文件
redis-cli --eval 脚本文件路径 参数..
EVAL
EVAL script numkeys key [key ...] arg [arg ...]
例如:
EVALSHA
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
应用
# 1: 项目启动时,建立redis连接并验证后,先加载所有项目中使
用的lua脚本(script load);
# 2: 项目中若需要热更新,通过redis-cli script flush;然
后可以通过订阅发布功能通知所有服务器重新加载lua脚本;
# 3:若项目中lua脚本发生阻塞,可通过script kill暂停当前阻
塞脚本的执行;
ACID特性分析:
A 原子性;事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败;redis 不支持回滚;即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。
C 一致性;事务的前后,所有的数据都保持一个一致的状态,不能违反数据的一致性检测。这里的一致性是指预期的一致性,而不是异常后的一致性。所以 redis 也不满足;这个争议很大:
redis 能确保事务执行前后的数据的完整约束。但是并不满足业务功能上的一致性。比如转账功能,一个扣钱一个加钱。可能出现扣钱执行错误,加钱执行正确,那么最终还是会加钱成功,系统凭空多了钱。
I 隔离性;各个事务之间互相影响的程度;redis 是单线程执行,天然具备隔离性。文章来源:https://www.toymoban.com/news/detail-603801.html
D 持久性;redis 只有在 aof 持久化策略的时候,并且需要在redis.conf 中 appendfsync=always 才具备持久性。实际项目中几乎不会使用 aof 持久化策略。
lua 脚本满足原子性和隔离性;一致性和持久性不满足。文章来源地址https://www.toymoban.com/news/detail-603801.html
到了这里,关于使用lua脚本操作redis的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!