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 可以看到数据都可以顺利的压入列队当中。