redis的事务详解-lua脚本方式

1、什么是事务?

事务就是将多条命令打包成一个不可分割的整体进行执行,在事务中的语句执行的过程中,不会被其他的命令插队。

2、事务的基本特性

原子性:事务是一个打包的整体命令,执行的过程中按照一个整体去执行,不会被其他的redis客户端发送的命令插队。

一致性:
① 类型一致性:在事务执行的过程中,对于数据的类型操作不能修改,例如不能对一个string类型的value执行lpop的操作。
②数据一致性:例如对于一个银行的余额表,A给B转账50元后,A的余额减少50,B的余额增加50,但是数据库中整体的余额数量是不变的。

隔离性:事务执行的过程中,对于其他redis客户端是不可变的。

持久性:redis本身提供了RDB和AOF的持久化机制。
注:只有AOF的同步写回这一持久化策略才是真正可靠的,除了同步写回外,AOF和RDB所有的持久化都是不可靠的。

3、为什么需要事务?

试想需要实现一个给value值翻倍的业务。

如果没有事务?应该怎么做呢?

没有事务的处理流程:

客户端发送 get key 给 redis,redis执行后返回结果给客户端。客户端拿到了key的value,然后发送 set key value * 2 给redis执行,redis执行后返回结果给客户端。

看似完美无缺,但是这样有很严重的缺陷。

如果redis服务器上只有一条连接,那么所有的命令执行都是基于这个连接发送的命令的顺序。这样做是没有问题的,但是如果Redis服务器上有多个客户端连接,这样做问题就非常的大了。

上述方式存在的隐患:

如果一个客户端在获取值后,发送 set key value * 2,这个 key 又被其他 redis 客户端所修改,那么 set key value * 2 就失去了对key翻倍的意义。
redis的事务详解-lua脚本方式_第1张图片

4、 redis事务的处理流程

当客户端发送mutli后,redis会为客户端创建一个事务队列。

然后客户端发送 1号命令 给redis,redis回复接收结果。

客户端再发送 2号命令给 redis,redis回复接收结果。

当客户端发送exec给redis后,redis执行事务队列当中的命令。

但是这样也会有问题,如果 事务 在打包命令 的过程中,其他

redis客户端就已经将这个值更改了怎么办?

redis中提供了解决方案:

redis中提供了watch,提供对某一个key的监视,在开启事务前,先用watch对某一个 key 进行观察,如果事务在执行的过程中。发现当前修改的key与观察的值不一致,事务会执行失败。

watch本身是一个乐观锁的思想,但是watch本身有很大的缺陷,那就是 : 在写业务时会非常麻烦。试想,如果watch了一个key,但是这个key频繁的被其他redis客户端修改的话,那么在服务器的业务层面需要不断的对这个事务进行重试,直到事务能够成功执行。

所以,在开发中,如果要使用到redis事务,采用watch是不合适的!

5、如何提供便于业务处理的事务

redis当中内嵌了lua虚拟机,redis提供了对于lua脚本的解析能力。

客户端使用事务的时候,可以使用lua语句,将事务的逻辑处理

放在lua脚本当中去执行,这样就可以防止 事务 执行之前,key值已经发生改变的情况!
在这里插入图片描述

一般在使用lua脚本之前,会先向redis服务器发送lua脚本。使用script load 命令将写好的lua脚本发送给redis服务器,redis会使用sha1算法对lua脚本计算生成一个哈希值(长度为40的字符串)返回给客户端,客户端对这个哈希值进行保存,就可以使用lua脚本向redis发送lua脚本执行事务了!

为什么需要先向redis传递lua脚本呢?

1、因为lua脚本的代码可能很长,如果每次都按照字符串的方式把lua脚本传递过去后再执行,那么对于redis服务器的带宽压力就太大了!如果redis本身有lua脚本,我们只需要传入40长度的字符串哈希值就可以选择对应的lua脚本执行,对redis的带宽占用非常小。

你可能感兴趣的:(linux服务器开发,redis,lua,数据库)