事务保证原子性操作,在redis 中实现事务和mysql中实现事务的方法有些不一样。
在 mysql中实现事务,一般是启动一个事务,然后执行 select ... for update 对某个要操作行进行锁定,然后如果并发的进程处理到锁定的行时,判定改行是否被其他的进程正在读(被锁定),如果是,则等待锁释放,然后继续执行结下来的操作,这也就是所谓的悲观锁。
在redis中实现事务也是有多个方法的,比如用 watch 监控某个key是否被其他的进程修改,watch乐观锁的实现方案,也就是说,先假定所有的进程之间的数据操作之间没有任何交集,执行一系列的操作,在最后提交的时候,如果发现被监控的key已经被其他的进程修改了(前面的假定失败),则提交时则返回false。
php中用redis 的 watch 实现的代码如下:
<?php //创建redis连接 $redis = new \Redis(); $redis->connect('127.0.0.1', 6379); //被监控的键 $key = 'watchkey'; //监控 $key,一定要在事务前监控这个键,因为在执行 multi 命令后,所有的命令将会进入到一个redis队列,然后保证这些命令可以不被其他程序打扰的情况下依次执行,这也是redis实现原子操作的方法 $redis->watch($key); //启用原子操作(事务) $redis->multi(); //为了测试结果,休眠3秒 sleep(3); //修改被监控的键值,incr 是redis 的计数器,原子性操作,每次执行这个命令,将给 $key 自增 1 $redis->incr($key); //在事务内得所有操作都将返回 redis 连接对象,只有在执行 exec 返回结果中,所有的返回数据将放到数组中返回 $redis->get($key); //执行事务,如果事务执行失败则返回false,正确则返回事务中的所有返回结果 $r = $redis->exec(); var_dump($r);
把上面的程序保存到t.php中,然后在命令行执行三次,等待执行结果:
我们发现,只有第一次执行是成功的,接下来执行的都是失败的。在redis-cli查看 watchkey 的结果,发现也仅仅第一个事务被正确执行了。