/** * 添加锁 * @param unknown $key_name 键的名称 * @param unknown $uniqid 唯一值 * @param unknown $key_expire 键的过期时间 * @return int 0失败,1成功 */ static function lock($key_name, $uniqid, $key_expire) { $lua_script = <<<EOF local flag = redis.call("setnx", KEYS[1], ARGV[1]) if tonumber(flag) > 0 then redis.call('expire', KEYS[1], ARGV[2]) return redis.call('get', KEYS[1]) else return 0 end EOF; $redis = MyRedisService::getInstance(); return $redis->eval($lua_script, 1, $key_name, $uniqid, $key_expire); } /** * 释放锁 * @param unknown $key_name 键名称 * @param unknown $key_val 键值校验 * @return int 0失败,1成功 */ static function unlock($key_name, $key_val) { $lua_script = <<<EOF local lockKey = redis.call('get', KEYS[1]) local lk = ARGV[1] if lockKey == lk then return redis.call('del', KEYS[1]) else return 0 end EOF; $redis = MyRedisService::getInstance(); return $redis->eval($lua_script, 1, $key_name, $key_val); } public function index() { //键名 $key_name = 'index'; //key过期时间 $key_expire = 1; //键的唯一标识 $uniqid = uniqid(null, true).microtime(); //加锁 $key_val = self::lock($key_name, $uniqid, $key_expire); //加锁成功,开始执行以下代码 if($key_val > 0) { try { $redis = MyRedisService::getInstance(); //从数据库或者redis中得到库存 $store_nums = $redis->get("store_nums"); if($store_nums > 0) { $redis->decrby("store_nums", 1); echo "去库存成功,剩余:".$redis->get('store_nums')."<br>"; } else { echo "库存不足<br>"; } } catch (\Exception $e) { //如果代码抛出异常,则直接删除key $redis->del($key_name); } } //释放锁 $res = self::unlock($key_name, $key_val); //如果释放锁失败,则直接手动删除key if(intval($res) === 0) { $redis->del($key_name); } }