yii2 redis扩展
yii2 2017-04-25 14:07:45

参考资料:http://www.yiichina.com/tutorial/904

 

1、redis扩展在2.6版本以前,set方法有改变,所以,先记录一下高版本的方式:

PHP Code复制内容到剪贴板
  1. // 增加配置文件,上面的fileCache 是文件缓存,随便用不用,删了也可以  
  2. 'components' => [  
  3.         'fileCache' => [  
  4.             'class' => 'yii\caching\FileCache',  
  5.             'dirMode' => 0777 // 防止console生成的目录导致web账户没写权限  
  6.         ],  
  7.         'redis' => [  
  8.             'class' => 'yii\redis\Cache',  
  9.             'redis' => [  
  10.                 'hostname' => 'localhost',  
  11.                 'port' => 6379,  
  12.                 'database' => 0,  
  13.             ]  
  14.         ],  

redis的方法就是,get,set,如果是数组,高版的redis是会对value进行序列化,然后读取的时候反序列化的

来试一下,第三个参数表示过期时间:

PHP Code复制内容到剪贴板
  1. <?php  
  2. $expire = 60*60;  
  3. $user_cart_rediskey = "key1";  
  4.   
  5. $transaction = \Yii::$app->db->beginTransaction();  
  6. try{  
  7.     // 如果该用户购物车没有数据  
  8.     $arr1 = [  
  9.         $course_id => $carts[0]  
  10.     ];  
  11.     $r = \Yii::$app->redis->set($user_cart_rediskey,$arr1,$expire);  
  12.     if(!$r){  
  13.         throw new \Exception('下手太快,道理拥堵,请重试!');  
  14.     };  
  15.   
  16.     $arr2 = [  
  17.         $plan_cart_rediskey => $carts[0]  
  18.     ];  
  19.     $r = \Yii::$app->redis->set($plan_cart_rediskey,$arr2,$expire);  
  20.     if(!$r){  
  21.         throw new \Exception('购物车更新失败,请重试!');  
  22.     };  
  23.   
  24.     //以上执行都成功,则对数据库进行实际执行  
  25.     $transaction->commit();  
  26.     return $this->buildResponse('success', 200, 'success to add cart');  
  27.   
  28. }catch (\Exception $e){  
  29.     //如果抛出错误则进入catch,先callback,然后捕获错误,返回错误  
  30.     $transaction->rollBack();  
  31.     return $this->buildResponse('error', 400, $e->getMessage());  
  32. }  
  33. ?>  

 

2、BUT 我遇到了一个redis版本是2.4的...  好吧,咱们来改一下,第三个参数过期时间是报错的,来看一下报错信息:

PHP Code复制内容到剪贴板
  1. Redis error: ERR wrong number of arguments for 'set' command\nRedis command was: SET 7615faba42795b1fb018980897442bcf a:2:{i:0;a:1:{i:82;a:4:{s:9:\"course_id\";s:2:\"82\";s:5:\"price\";s:4:\"1.00\";s:11:\"unique_code\";s:5:\"wujin\";s:6:\"status\";i:1;}}i:1;N;} PX 3600000"  

 

好了,来改吧,首先是配置文件:

PHP Code复制内容到剪贴板
  1. 'redis' => [  
  2.     'class' => 'yii\redis\Connection',  
  3.     'hostname' => 'localhost',  
  4.     'port' => 6379,  
  5.     'database' => 0,  
  6. ],  

然后,GET和SET 照常用,不过得自己序列化,或者JSON了哈

可以在components新建一个Cache类:

PHP Code复制内容到剪贴板
  1. class Redis  
  2. {  
  3.     /** 
  4.      * 获取指定值 
  5.      * @param $key 
  6.      * @return mixed 
  7.      */  
  8.     public static function get($key){  
  9.         $value = \Yii::$app->redis->get($key);  
  10.         $value_serl = @unserialize($value);  
  11.         if(is_object($value_serl)||is_array($value_serl)){  
  12.             return $value_serl;  
  13.         }  
  14.         return $value;  
  15.     }  
  16.   
  17.     /** 
  18.      * @desc 获取锁键名 
  19.      */  
  20.     public static function getLockCacheKey($key)  
  21.     {  
  22.         return "lock_{$key}";  
  23.     }  
  24.   
  25.     /** 
  26.      * @desc 获取锁 
  27.      * @param $key              string | 要上锁的键名 
  28.      * @param null $timeout     int | 上锁时间 
  29.      * @return bool 
  30.      */  
  31.     public static function getLock($key$timeout = NULL)  
  32.     {  
  33.         $timeout = $timeout ? $timeout : 10;  
  34.         $lockCacheKey = self::getLockCacheKey($key);  
  35.   
  36.         $expireAt = time() + $timeout;  
  37.         $isGet = (bool)\Yii::$app->redis->setnx($lockCacheKey$expireAt);  
  38.         if ($isGet) {  
  39.             return true;  
  40.         }else if(!$isGet){  
  41.             usleep(1);  
  42.             $time = time();  
  43.             $oldExpire = \Yii::$app->redis->get($lockCacheKey);  
  44.   
  45.             if ($oldExpire >= $time) {  
  46.                 return true;  
  47.             }  
  48.             $newExpire = $time + $timeout;  
  49.             $expireAt = \Yii::$app->redis->getset($lockCacheKey$newExpire);  
  50.             if ($oldExpire != $expireAt) {  
  51.                 return false;  
  52.             }  
  53.             return true;  
  54.         }  
  55.   
  56.     }  
  57.   
  58.     /** 
  59.      * @desc 释放锁 
  60.      * @param $key          string | 加锁的字段 
  61.      * @param $newExpire    int | 加锁的截止时间 
  62.      * @return bool         | 是否释放成功 
  63.      */  
  64.     public static function releaseLock($key)  
  65.     {  
  66.         $lockCacheKey = self::getLockCacheKey($key);  
  67.         return \Yii::$app->redis->del($lockCacheKey);  
  68.     }  
  69.   
  70.   
  71.     /** 
  72.      * 设置新的键值和过期时间 
  73.      * @param $key 
  74.      * @param $value 
  75.      * @param $expire  过期时间,可选 
  76.      * @return mixed 
  77.      */  
  78.     public static function set($key,$value,$expire = 0){  
  79.         if(is_object($value)||is_array($value)){  
  80.             $value = serialize($value);  
  81.         }  
  82.         if($expire){  
  83.             $r = \Yii::$app->redis->setex($key,$expire,$value);  
  84.             return $r;  
  85.         }else{  
  86.             return \Yii::$app->redis->set($key,$value);  
  87.         }  
  88.     }  
  89.   
  90.     /** 
  91.      * 返回指定键的过期时间,会有-1的存在 
  92.      * @param $key 
  93.      * @return mixed 
  94.      */  
  95.     public static function getExpireTime($key){  
  96.         return \Yii::$app->redis->ttl($key);  
  97.     }  
  98.   
  99.     /** 
  100.      * 设置指定键的过期时间 
  101.      * @param $key 
  102.      * @param $expire 
  103.      * @return mixed 
  104.      */  
  105.     public static function expire($key,$expire){  
  106.         return \Yii::$app->redis->expire($key,$expire);  
  107.     }  
  108.   
  109.     /** 
  110.      * 查找所有相似值 
  111.      * @param $key    如 foo* 
  112.      * @return mixed 
  113.      */  
  114.     public static function getLikeValues($key){  
  115.         $r = \Yii::$app->redis->keys($key);  
  116.         return $r;  
  117.     }  
  118.   
  119.     public static function lpush($key,$value){  
  120.         if(is_object($value)||is_array($value)){  
  121.             $value = serialize($value);  
  122.         }  
  123.         return \Yii::$app->redis->lpush($key,$value);  
  124.     }  
  125. }  

 这里有一个大大的坑,如果有过期时间,时间是放在中间的,然后value是搁在后面的!

 

试了一下队列与原子,判断还是出错,

PHP Code复制内容到剪贴板
  1. $plan_cart = Redis::getLikeValues("course:".$plan_id.":*"); //获取该计划下购物车的json  
  2. $cartNum = count($plan_cart);  
  3. if($cartNum > ($courses['limited']-1)){  
  4.     exit('该课程已经被购完');  
  5. };  
  6.   
  7. // 像这种的并发高了以后完全不能用...,来加个锁:  
  8.   
  9. /* 锁定 */  
  10. $lock_key = "course:".$plan_id;  
  11. $lock = Redis::getLock($lock_key);  
  12. if(!$lock){  
  13.     exit('道路拥挤,请稍候再试~');  
  14. }  
  15. $plan_cart = Redis::getLikeValues("course:".$plan_id.":*"); //获取该计划下购物车的json  
  16. $cartNum = count($plan_cart);  
  17. if($cartNum > ($courses['limited']-1)){  
  18.     exit('该课程已经被购完');  
  19. };  
  20. Redis::releaseLock($lock_key);  //解锁  
  21. /* end */  
  22.   
  23.   
  24. 不知道是不是我哪里逻辑写的不对,反正我加了两次锁,第一次是加入购物车的动作时,还有一次在判断完以后准备 写入用户购物redis数据的时候还加了一次锁  

 

 

 

本文来自于:http://www.yoyo88.cn/study/yii2/104.html

上一篇 yii2 console
Powered by yoyo苏ICP备15045725号