2019独角兽企业重金招聘Python工程师标准>>>
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
* @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,
*
* array(
* 'components'=>array(
* 'cache'=>array(
* 'class'=>'CRedisCache',
* 'hostname'=>'localhost',
* 'port'=>6379,
* 'database'=>0,
* ),
* ),
* )
*
*
* The minimum required redis version is 2.0.0.
*
* @author Carsten Brandt
* @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:
*
* true
for commands that return "status reply".
* string
for commands that return "integer reply"
* as the value is in the range of a signed 64 bit integer.
* string
or null
for commands that return "bulk reply".
* array
for commands that return "Multi-bulk replies".
*
* 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
可以看到数据都可以顺利的压入列队当中。