Redis事务和锁
Redis事务 事务是指一个完整的动作,要么全部执行,要么什么也没有做。Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。 Redis 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。 Redis 的事务不是原子性,但是Redi执行每一个命令都是原子性的 举例:INCR在redis中是自增,即使多个客户端对同一个密钥发出INCR,也永远不会进入竞争状态。例如,客户机1读取“10”,客户机2同时读取“10”,两者都增加到11,并将新值设置为11,这样的情况永远不会发生。最终的值将始终是12。 这个案例是官网提出来的:https://redis.io/docs/data-types/tutorial/ 事务一般都是为原子性而生,既然Redis事务没有原子性,那他存在的意义是什么? redis事务的主要作用就是串联多个命令防止 别的命令插队。 官网介绍:https://redis.com.cn/redis-transaction.html Redis事务 - 基本使用 Redis 在形式上看起来也差不多,MULTI、EXEC、DISCARD这三个指令构成了 redis 事务处理的基础: MULTI:用来组装一个事务,从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,redis会将之前的命令依次执行。 EXEC:用来执行一个事务 DISCARD:用来取消一个事务 所有的指令在 exec 之前不执行,而是缓存在服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运行结果。因为 Redis 的单线程特性,不用担心自己在执行队列的时候被其它指令打搅,可以保证他们能得到的有顺序的执行。 取消事务,放弃执行事务块内的所有命令。 组队中某个命令出现了错误报告,执行时整个队列中所有的命令都会被取消。 命令组队的过程中没有问题,执行中出现了错误会导致部分成功部分失败。 悲观锁&乐观锁 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人拿到这个数据就会block直到它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在做操作之前先上锁。 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去那数据的时候都认为别人不会修改,所以不会上锁,但是在修改的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。redis就是使用这种check-and-set机制实现事务的。 watch监听 WATCH:在执行multi之前,先执行watch key1 [key2 …],可以监视一个或者多个key,若在事务的exec命令之前这些key对应的值被其他命令所改动了,那么事务中所有命令都将被打断,即事务所有操作将被取消执行。 unwatch:取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行UNWATCH 了。 简单示例秒杀场景 <?php // 连接Redis $redis = new Redis(); $redis->connect('127.0.0.1',6379); $redis->watch('sales'); $sales = $redis->get('sales'); $store = 10; if($sales >= $store){ exit('结束'); } // 事务 $redis->multi(); $redis->incr('sales'); $res = $redis->exec(); if($res){ // 库存更新....