游戏中一些常用的功能,仅仅使用redis提供的命令来实现,恐怕难度比较大。好在redis支持lua,能让一系列的操作变为原子操作,让这些常用却又麻烦的功能变的简单了,当然这需要小量的性能损失,别的不多说,懂的自然懂,不懂的看了就懂了,上代码: class MyStorage extends Redis { public function safeDecr($key, $num) { $script = "local old=redis.call('get', KEYS[1]);\n"; $script.= "if not old or old+0 < ARGV[1]+0 then return false;end;"; $script.= "return redis.call('decrBy', KEYS[1], ARGV[1]);\n"; return $this->eval($script, array($key, $num), 1); } public function safeHDecr($key, $member, $num) { $script = "local old=redis.call('hGet', KEYS[1], ARGV[1]);\n"; $script.= "if not old or old+0 < ARGV[2]+0 then return false;end;"; $script.= "redis.call('hIncrBy', KEYS[1], ARGV[1], -ARGV[2]);\n"; $script.= "return true;"; return $this->eval($script, array($key, "", $member, $num), 2); } public function lock($key, $now, $expire) { $script = "local old=redis.call('get', KEYS[1]);\n"; $script.= "if old and ARGV[1]+0 < old+0 then return false;end;\n"; $script.= "redis.call('set', KEYS[1], ARGV[2]);\n"; $script.= "return true;"; return $this->eval($script, array($key, "", $now, $expire), 2); } public function hlock($key, $member, $now, $expire) { $script = "local old=redis.call('hGet', KEYS[1], ARGV[1]);\n"; $script.= "if old and ARGV[2]+0 < old+0 then return false;end;\n"; $script.= "redis.call('hSet', KEYS[1], ARGV[1], ARGV[3]);\n"; $script.= "return true;"; return $this->eval($script, array($key, "", "", $member, $now, $expire), 3); } public function rankSwap($key, $r1, $r2) { $script = "local r1score=redis.call('zScore', KEYS[1], ARGV[1]);\n"; $script.= "local r2score=redis.call('zScore', KEYS[1], ARGV[2]);\n"; $script.= "redis.call('zAdd', KEYS[1], r2score, ARGV[1]);\n"; $script.= "return redis.call('zAdd', KEYS[1], r1score, ARGV[2]);\n"; return $this->eval($script, array($key, "", $r1, $r2), 2); } } $redis = new MyStorage(); //场景1:需要对某个key进行decr操作,但是又不能让他为负数(比如某个物品限量销售) $redis->safeDecr('mygold', 10);//如果mygold的值小于10,那么会返回false //场景2:需要对hashtable下某个Key做decr操作,但又不能让他为负数(比如用户的金币、游戏币等) $redis->safeHDecr('mygold2', 'gold', 10); //场景3:锁定某个key,并且让他带有过期时间 $now = time(); $redis->lock('mylock', $now, $now + 5);//5秒后过期,再此期间再进行加锁,会返回false //场影4:锁定hashtable中某个key,并且带过期时间(当然你可以直接用lock,但是这样你要清理所有相关的锁,就必须来一次keys了) $now = time(); $redis->hlock('mylock', 'lock', $now, $now + 5); //场景5:对排名进行原子的交换(比如游戏中的排行榜,如果你要取出来再zadd回去,估计bug一大堆,当然这个可以用策划来弥补,比如胜利了+N积分) $redis->rankSwap('myrank', 'r1', 'r2');