用layui做的网站,抚州市企业网站建设,dede自定义网站地图,创新驱动发展战略纲要Redis中的事务机制
概述。
事务表示一组动作#xff0c;要么全部执行#xff0c;要么全部不执行。例子如下。 Redis提供了简单的事务功能#xff0c;讲一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始#xff0c;exec命令代表事务结束#x…Redis中的事务机制
概述。
事务表示一组动作要么全部执行要么全部不执行。例子如下。 Redis提供了简单的事务功能讲一组需要一起执行的命令放到multi和exec两个命令之间。multi命令代表事务开始exec命令代表事务结束如果要停止事务的执行可以使用discard命令代替exec命令即可。它们之间的命令是原子执行的
例子
例如在社交网站上用户A关注了用户B,那么需要在用户A的关注表中加入用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行要么全部不执行否则会出现数据不一致的情况
例如下面代码实现了用户关注问题
127.0.0.1:6379 SADD u:a:follow ub
QUEUED
127.0.0.1:6379 SADD u:b:fans ua
QUEUED可以看到SADD命令此时的返回结果是QUEUED代表命令并没有真正执行而是暂时保存在Redis中的一个缓存队列(所以discard也只是丢弃这个缓存队列中的未执行命令并不会回滚已经操作过的数据这一点要和关系型数据库的Rollback操作区分开)。如果此时另一个客户端执行下方代码返回结果应该是0
127.0.0.1:6379 SISMEMBER u:a:follow ub
(integer) 0只有当exec执行后用户A关注用户B的行为才算完成如下所示exec返回的两个结果对应SADD命令
127.0.0.1:6379 multi
OK
127.0.0.1:6379 SADD u:a:follow ub
QUEUED
127.0.0.1:6379 SADD u:b:fans ua
QUEUED
127.0.0.1:6379 exec
1) (integer) 1
2) (integer) 1另一个客户端:
127.0.0.1:6379 SISMEMBER u:a:follow ub
(integer) 0
127.0.0.1:6379 SISMEMBER u:a:follow ub
(integer) 1错误处理机制
如果事务中的命令出现错误Redis的处理机制也不尽相同
1.命令错误
例如下面操作将set写成了SETT属于语法错误会造成整个事务无法执行
127.0.0.1:6379 set txkey hello
OK
127.0.0.1:6379 set txcount 100
OK
127.0.0.1:6379 mget txkey txcount
1) hello
2) 100
127.0.0.1:6379 multi
OK
127.0.0.1:6379 sett txkey world
(error) ERR unknown command sett, with args beginning with: txkey, world,
127.0.0.1:6379 incr txcount
QUEUED
127.0.0.1:6379 exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379 mget txkey txcount
1) hello
2) 1002.运行时错误
例如用户B在添加粉丝列表时误把SADD命令(针对集合)写成了ZADD命令(针对有序集合)这种就是运行时命令因为语法时正确的:
127.0.0.1:6379 SADD u:b:fans ua
(integer) 1
127.0.0.1:6379 multi
OK
127.0.0.1:6379 SADD u:c:follow ub
QUEUED
127.0.0.1:6379 ZADD u:b:fans 1 uc
QUEUED
127.0.0.1:6379 exec
1) (integer) 1
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379 sismember u:c:follow ub
(integer) 1可以看到Redis并不支持回滚功能SADD u:c:follow ub命令已经执行成功开发人员需要自己修复这类问题。
3.WATCH机制
有些应用场景需要在事务之前确保事务中的key没有key没有被其他客户端修改过才执行事务否则不执行(类似乐观锁)。Redis提供了watch命令来解决这类问题。 客户端1
127.0.0.1:6379 set testwatch java
OK
127.0.0.1:6379 watch testwatch
OK
127.0.0.1:6379 multi
OK客户端2
127.0.0.1:6379 get testwatch
java
127.0.0.1:6379 append testwatch python
(integer) 10客户端1继续:
127.0.0.1:6379 append testwatch jedis
QUEUED
127.0.0.1:6379 exec
(nil)
127.0.0.1:6379 get testwatch
javapython可以看到客户端1在执行multi之前执行了watch命令客户端2在客户端1执行exec之前修改了key值造成可客户端1事务没有执行(exec结果为nil)
Pipeline和事务的区别
1.pipeline是客户端的行为对于服务器来说是透明的可以认为服务器无法区分客户端发送来的查询命令是以普通命令的形式还是以pipeline的形式发送到服务器的2.而事务则是实现在服务器端的行为用户执行MULTI命令时服务器会将对应这个用户的客户端对象设置为一个特殊的状态在这个状态下后续用户执行管的查询命令不会被真的执行,而是被服务器缓存起来直到用户执行EXEC命令为止服务器会将这个用户对应的客户端对象中缓存的命令按照提交的顺序依次执行3.应用pipeline可以提高服务器的吞吐能力并提高Redis处理查询请求的能力。但是这里存在一个问题当通过pipeline提交的查询命令数据较少可以被内核缓冲区所容纳时Redis可以保证这些命令执行的原子性。然而一旦数据量过大超过了内核缓冲区的接收大小那么命令的执行将会被打断原子性也就无法得到保证。因此pipeline只是一种提升服务器吞吐能力的机制如果想要命令以事务的方式原子性地被执行还是需要事务机制或者使用更高级的脚本功能以及模块功能4.可以将事务和pipeline结合起来使用减少事务地命令在网络上的传输时间将多次网络IO缩减为一次网络IO.Redis提供了简单的事务之所以说它简单主要时因为它不支持事务中的回滚特性同时无法实现命令之间的逻辑关系计算当然也体现了Redis的keep it simple的特性
Lua脚本
Redis在2.6推出了脚本功能允许开发者使用Lua语言编写脚本传到Redis中执行使用脚本的好处如下:
1.减少网络开销:本来5次网络请求的操作可以用一个请求完成原先5次请求的逻辑放在Redis服务器上完成使用脚本减少了网络往返时延跟管道类似2.源自操作:Redis会将整个脚本作为一个整体执行中间不会被其他命令插入,管道不是原子的redis的批量操作命令(类似mset)是原子的3.替代redis的事务功能:redis自带的事务功能很鸡肋而redis的lua脚本几乎实现了常规的事务功能官方推荐如果要使用redis的事务功能可以用redis lua替代 A Redis script is transactional by definition, so everything you can do with a Redis transaction, you can also do with a script,and usually the script will be both simpler and faster.