Yii 框架中使用redis缓存数据

Yii框架中可以自由配置缓存方式,比如最常用的memcache/memcahed,只需要在config中添加如下配置信息即可。

Source code	          
'cache' => array (
    'class' => 'system.caching.CMemCache',
    'servers' => array (
          array (
            'host' => '127.0.0.1',
            'port' => 11211,
            'weight' => 60 
          ) 
        ),
        'hashKey' => false,
        'serializer' => false,
        'useMemcached' => true 
    )
使用方法也很方便。

Source code	          

  Yii::app()->cache->set('aaaa','value');
Radis 作为一个内存型数据库,我们通常会将它作为可长时间将数据存贮到内存中的缓存系统,事实上不能及时做持久化处理的存储系统都是不稳定的。对于传统的key-value缓存系统而言,radis又同时支持多种数据结构(String,List,Set,Map,StoredSet),有关支持的数据类型可以参考redis中文站点 猛击我 。

支持多种数据结构意味着我们能够利用这些数据结构特性,展开一些特定的业务,比如在之前的项目当中使用的时间轴。如果用传统数据库实现性能会相当低下,既要考虑多种表交叉重组,又要考虑重组后的分页问题。如果用非关系型数据库就会很方便的处理,利用List特性就可以方便的“压入”用户的历史数据。

先来看一下如何配置一个redis缓存。

Source code	          
'redis_cache' => array (
  'class' => 'system.caching.CRedisCache',
  'hostname' =>'127.0.0.1',
  'port'=>6379,
  'password'=>'123456',
  'database'=>0
) 
//使用方法
Yii::app()->redis_cache->set('aaaa','value');
利用Yii框架中的caching.CRedisCache类,password是部署服务器当中的auth配置。

使用方法和使用memcache/memcahced中的cache一样,直接set/get即可。

看一下CRedisCached这个实现类

Source code	          
<?php
/**
 * CRedisCache class file

 *
 * @author Carsten Brandt <[email protected]>

 * @link http://www.yiiframework.com/

 * @copyright 2008-2013 Yii Software LLC

 * @license http://www.yiiframework.com/license/

 */
/**
 * CRedisCache implements a cache application component based on {@link http://redis.io/ redis}.

 *
 * CRedisCache needs to be configured with {@link hostname}, {@link port} and {@link database} of the server

 * to connect to. By default CRedisCache assumes there is a redis server running on localhost at

 * port 6379 and uses the database number 0.

 *
 * CRedisCache also supports {@link http://redis.io/commands/auth the AUTH command} of redis.

 * When the server needs authentication, you can set the {@link password} property to

 * authenticate with the server after connect.

 *
 * See {@link CCache} manual for common cache operations that are supported by CRedisCache.

 *
 * To use CRedisCache as the cache application component, configure the application as follows,

 * <pre>
 * array(
 * 'components'=>array(

 * 'cache'=>array(

 * 'class'=>'CRedisCache',

 * 'hostname'=>'localhost',

 * 'port'=>6379,

 * 'database'=>0,

 * ),
 * ),
 * )
 * </pre>
 *
 * The minimum required redis version is 2.0.0.

 *
 * @author Carsten Brandt <[email protected]>

 * @package system.caching

 * @since 1.1.14

 */
class CRedisCache extends CCache

{
/**
* @var string hostname to use for connecting to the redis server. Defaults to 'localhost'.

*/
public $hostname = 'localhost' ;

/**
* @var int the port to use for connecting to the redis server. Default port is 6379.

*/
public $port = 6379 ;

/**
* @var string the password to use to authenticate with the redis server. If not set, no AUTH command will be sent.

*/
public $password ;

/**
* @var int the redis database to use. This is an integer value starting from 0. Defaults to 0.

*/
public $database = 0 ;

/**
* @var float timeout to use for connection to redis. If not set the timeout set in php.ini will be used: ini_get("default_socket_timeout")

*/
public $timeout = null ;

/**
* @var resource redis socket connection

*/
private $_socket ;

/**
* Establishes a connection to the redis server.

* It does nothing if the connection has already been established.

* @throws CException if connecting fails

*/
protected function connect ( )

{
$this -> _socket =@ stream_socket_client (

$this -> hostname . ':' . $this -> port ,

$errorNumber ,
$errorDescription ,

$this -> timeout ? $this -> timeout : ini_get ( "default_socket_timeout" )

) ;
if ( $this -> _socket )

{
if ( $this -> password !== null )

$this -> executeCommand ( 'AUTH' , array ( $this -> password ) ) ;

$this -> executeCommand ( 'SELECT' , array ( $this -> database ) ) ;

}
else
throw new CException ( 'Failed to connect to redis: ' . $errorDescription , ( int ) $errorNumber ) ;

}
/**
* Executes a redis command.

* For a list of available commands and their parameters see {@link http://redis.io/commands}.

*
* @param string $name the name of the command

* @param array $params list of parameters for the command

* @return array|bool|null|string Dependend on the executed command this method

* will return different data types:

* <ul>
* <li><code>true</code> for commands that return "status reply".</li>

* <li><code>string</code> for commands that return "integer reply"

* as the value is in the range of a signed 64 bit integer.</li>

* <li><code>string</code> or <code>null</code> for commands that return "bulk reply".</li>

* <li><code>array</code> for commands that return "Multi-bulk replies".</li>

* </ul>
* See {@link http://redis.io/topics/protocol redis protocol description}

* for details on the mentioned reply types.

* @trows CException for commands that return {@link http://redis.io/topics/protocol#error-reply error reply}.

*/
public function executeCommand ( $name , $params = array ( ) )

{
if ( $this -> _socket === null )

$this -> connect ( ) ;

array_unshift ( $params , $name ) ;

$command = '*' . count ( $params ) . " \r \n " ;

foreach ( $params as $arg )

$command .= '$' . strlen ( $arg ) . " \r \n " . $arg . " \r \n " ;

fwrite ( $this -> _socket , $command ) ;

return $this -> parseResponse ( implode ( ' ' , $params ) ) ;

}
/**
* Reads the result from socket and parses it

* @return array|bool|null|string

* @throws CException socket or data problems

*/
private function parseResponse ( )

{
if ( ( $line = fgets ( $this -> _socket ) ) === false )

throw new CException ( 'Failed reading data from redis connection socket.' ) ;

$type = $line [ 0 ] ;

$line = substr ( $line , 1 ,- 2 ) ;

switch ( $type )
{
case '+' : // Status reply

return true ;
case '-' : // Error reply

throw new CException ( 'Redis error: ' . $line ) ;

case ':' : // Integer reply

// no cast to int as it is in the range of a signed 64 bit integer

return $line ;
case '$' : // Bulk replies

if ( $line == '-1' )

return null ;
$length = $line + 2 ;

$data = '' ;
while ( $length > 0 )

{
if ( ( $block = fread ( $this -> _socket , $length ) ) === false )

throw new CException ( 'Failed reading data from redis connection socket.' ) ;

$data .= $block ;
$length -= ( function_exists ( 'mb_strlen' ) ? mb_strlen ( $block , '8bit' ) : strlen ( $block ) ) ;

}
return substr ( $data , 0 ,- 2 ) ;

case '*' : // Multi-bulk replies

$count = ( int ) $line ;

$data = array ( ) ;
for ( $i = 0 ; $i < $count ; $i ++ )

$data [ ] = $this -> parseResponse ( ) ;

return $data ;
default :
throw new CException ( 'Unable to parse data received from redis.' ) ;

}
}
/**
* Retrieves a value from cache with a specified key.

* This is the implementation of the method declared in the parent class.

* @param string $key a unique key identifying the cached value

* @return string|boolean the value stored in cache, false if the value is not in the cache or expired.

*/
protected function getValue ( $key )

{
return $this -> executeCommand ( 'GET' , array ( $key ) ) ;

}
/**
* Retrieves multiple values from cache with the specified keys.

* @param array $keys a list of keys identifying the cached values

* @return array a list of cached values indexed by the keys

*/
protected function getValues ( $keys )

{
$response = $this -> executeCommand ( 'MGET' , $keys ) ;

$result = array ( ) ;

$i = 0 ;
foreach ( $keys as $key )

$result [ $key ] = $response [ $i ++ ] ;

return $result ;
}
/**
* Stores a value identified by a key in cache.

* This is the implementation of the method declared in the parent class.

*
* @param string $key the key identifying the value to be cached

* @param string $value the value to be cached

* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.

* @return boolean true if the value is successfully stored into cache, false otherwise

*/
protected function setValue ( $key , $value , $expire )

{
if ( $expire == 0 )
return ( bool ) $this -> executeCommand ( 'SET' , array ( $key , $value ) ) ;

return ( bool ) $this -> executeCommand ( 'SETEX' , array ( $key , $expire , $value ) ) ;

}
/**
* Stores a value identified by a key into cache if the cache does not contain this key.

* This is the implementation of the method declared in the parent class.

*
* @param string $key the key identifying the value to be cached

* @param string $value the value to be cached

* @param integer $expire the number of seconds in which the cached value will expire. 0 means never expire.

* @return boolean true if the value is successfully stored into cache, false otherwise

*/
protected function addValue ( $key , $value , $expire )

{
if ( $expire == 0 )
return ( bool ) $this -> executeCommand ( 'SETNX' , array ( $key , $value ) ) ;

if ( $this -> executeCommand ( 'SETNX' , array ( $key , $value ) ) )

{
$this -> executeCommand ( 'EXPIRE' , array ( $key , $expire ) ) ;

return true ;
}
else
return false ;
}
/**
* Deletes a value with the specified key from cache

* This is the implementation of the method declared in the parent class.

* @param string $key the key of the value to be deleted

* @return boolean if no error happens during deletion

*/
protected function deleteValue ( $key )

{
return ( bool ) $this -> executeCommand ( 'DEL' , array ( $key ) ) ;

}
/**
* Deletes all values from cache.

* This is the implementation of the method declared in the parent class.

* @return boolean whether the flush operation was successful.

*/
protected function flushValues ( )

{
return $this -> executeCommand ( 'FLUSHDB' ) ;

}
}
可以看出Yii并没有使用其他的redis扩展,现在流行的PHP redis连接方式主要有两种。其他参见 其他client

predis:一个不需要安装PHP扩展的连接Redis的组件包
PHP-redis:一个redis的php扩展
看源码可以看到,Yii使用的是stream_socket_client这种方式连接的redis服务器。我们模拟一下看看

Source code	          
$socket=@stream_socket_client(
    '127.0.0.1:6379',
    $errorNumber,
    $errorDescription,
    300
);
var_dump($socket);
使用这种方法可以顺利的连接到远程socket端口,其实以前如果用过的话就能知道,其实MySql也是可以用这种方式获得连接的。但不提倡,暂时先用这种方法,有时间再来利用扩展。

已经很强大了,可这满足不了我们目前的需要。该类集成自CCache只实现了其中的set get方法,其他的并没有实现,而更多地是需要我们借助executeCommand($name,$params=array())这个方法来完成我们想要的操作。所以我们需要对该方法做进一步封装,利用executeCommand。

我们首先扩展一个List左侧压入一个数据的操作

Source code	          

/**
 * @author Abel
 * email:[email protected]
 * 2014-1-17
 * UTF-8
 */
class ZRedisCache extends CRedisCache{
 
    /**
     * 左侧压入一个数据
     * @param String $key
     * @param String $value
     * @return int
     */
    public function lpush($key,$value){
        if(!is_string($value)){
            throw new Exception('The value type is not a string.If u want to push an array data.You can use JSON.');
        }
        $num = $this->executeCommand('LPUSH',array($key,$value));
        return intval($num);
    }
}
3F2258B8-1DE1-4794-812A-47AFA9507D76
可以看到数据都可以顺利的压入列队当中。


你可能感兴趣的:(Yii 框架中使用redis缓存数据)