Yii框架中内置好几个缓存类,其中有memcache的类,但是没有redis缓存类,由于项目中需要做主从架构,所以扩展了一下:

/**
* FileName:RedisCluster
* 配置说明
* 配置为1主多从 或者 1个独立的服务器
* 写往主的里面写
* 读是从从的里面读
* 'class'=>'RedisCache',
* 'servers'=>array(
* array(
* 'host'=>'IP1',
* 'port'=>'6380',
* 'master'=>true //主机
* ),
* array(
* 'host'=>'IP2',
* 'port'=>'6381'
* )
*
* 单独
* 'class'=>'RedisCache',
* 'servers'=>array(
* array(
* 'host'=>'IP1',
* 'port'=>'6380',
* ), * @author zhonghailin
* @version v1.0
* @since v1.0
* @Date 2015-3-10 下午4:57:02
*/
class ERedisCache extends CCache{ // 是否使用 M/S 的读写集群方案
private $_isUseCluster = false; // Slave 句柄标记
private $_sn = 0; // 服务器连接句柄
private $_linkHandle = array(
'master'=>null,// 只支持一台 Master
'slave'=>array(),// 可以有多台 Slave
);
//配置文件
private $_servers=array();
/**
* 构造函数
*
* @param boolean $isUseCluster 是否采用 M/S 方案
*/
/*
* 初始化
*/
public function init()
{
$this->keyPrefix = "";
parent::init();
if(is_array($this->_servers)){
foreach($this->_servers as $servers){
if($servers->master){
$this->_isUseCluster = true;//如果设置了主服务器那么就是1主多从
$this->connect($servers,true);
}else{
$this->connect($servers);
}
}
}
} /**
* @return array list of memcache server configurations. Each element is a {@link CMemCacheServerConfiguration}.
*/
public function getServers()
{
return $this->_servers;
} /**
* @param array $config list of memcache server configurations. Each element must be an array
* with the following keys: host, port, persistent, weight, timeout, retryInterval, status.
* @see http://www.php.net/manual/en/function.Memcache-addServer.php
*/
public function setServers($config)
{
foreach($config as $c)
$this->_servers[]=new CRedisServerConfiguration($c);
}
/**
* 连接服务器,注意:这里使用长连接,提高效率,但不会自动关闭
*
* @param array $config Redis服务器配置
* @param boolean $isMaster 当前添加的服务器是否为 Master 服务器
* @return boolean
*/
public function connect($config, $isMaster=false){
// default port
if(!isset($config->port)){
$config->port = 6379;
}
// 设置 Master 连接
if($isMaster){
$this->_linkHandle['master'] = new Redis();
$ret = $this->_linkHandle['master']->pconnect($config->host,$config->port);
}else{
// 多个 Slave 连接
$this->_linkHandle['slave'][$this->_sn] = new Redis();
$ret = $this->_linkHandle['slave'][$this->_sn]->pconnect($config->host,$config->port);
++$this->_sn;
}
return $ret;
} /**
* 关闭连接
*
* @param int $flag 关闭选择 0:关闭 Master 1:关闭 Slave 2:关闭所有
* @return boolean
*/
public function close($flag=2){
switch($flag){
// 关闭 Master
case 0:
$this->getRedis()->close();
break;
// 关闭 Slave
case 1:
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->close();
}
break;
// 关闭所有
case 2:
if(!empty( $this->_linkHandle['master'])){
$this->_linkHandle['master']->close();
}
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->close();
}
break;
}
return true;
} /**
* 得到 Redis 原始对象可以有更多的操作
*
* @param boolean $isMaster 返回服务器的类型 true:返回Master false:返回Slave
* @param boolean $slaveOne 返回的Slave选择 true:负载均衡随机返回一个Slave选择 false:返回所有的Slave选择
* @return redis object
*/
public function getRedis($isMaster=true,$slaveOne=true){
// 只返回 Master
if($isMaster){
return $this->_linkHandle['master'];
}else{
return $slaveOne ? $this->_getSlaveRedis() : $this->_linkHandle['slave'];
}
} /**
* 写缓存
*
* @param string $key 组存KEY
* @param string $value 缓存值
* @param int $expire 过期时间, 0:表示无过期时间
*/
public function setValue($key, $value, $expire=0){
// 永不超时
if($expire == 0){
if($this->_isUseCluster){
$ret = $this->getRedis()->set($key, $value);
}else{
$ret = $this->getRedis(false)->set($key, $value);
}
}else{
if($this->_isUseCluster){
$ret = $this->getRedis()->setex($key, $expire, $value);
}else{
$ret = $this->getRedis(false)->setex($key, $expire, $value);
}
}
return $ret;
} /**
* 读缓存
*
* @param string $key 缓存KEY,支持一次取多个 $key = array('key1','key2')
* @return string || boolean 失败返回 false, 成功返回字符串
*/
public function getValue($key){
// 是否一次取多个值
$func = is_array($key) ? 'mGet' : 'get';
// 使用了 M/S
return $this->_getSlaveRedis()->{$func}($key);
} /**
* 条件形式设置缓存,如果 key 不存时就设置,存在时设置失败
*
* @param string $key 缓存KEY
* @param string $value 缓存值
* @return boolean
*/
public function setnx($key, $value){
if($this->_isUseCluster){
return $this->getRedis()->setnx($key, $value);
}else{
return $this->getRedis(false)->setnx($key, $value);
} } /**
* 删除缓存
*
* @param string || array $key 缓存KEY,支持单个健:"key1" 或多个健:array('key1','key2')
* @return int 删除的健的数量
*/
public function remove($key){
if($this->_isUseCluster){
return $this->getRedis()->delete($key);
}else{
return $this->getRedis(false)->delete($key);
}
} /* (non-PHPdoc)
* @see BaseCache::delete()
*/
public function deleteValue($key){
if($this->_isUseCluster){
return $this->getRedis()->delete($key);
}else{
return $this->getRedis(false)->delete($key);
}
}
/**
* 值加加操作,类似 ++$i ,如果 key 不存在时自动设置为 0 后进行加加操作
*
* @param string $key 缓存KEY
* @param int $default 操作时的默认值
* @return int 操作后的值
*/
public function incr($key,$default=1){
if($default == 1){
return $this->getRedis()->incr($key);
}else{
return $this->getRedis()->incrBy($key, $default);
}
} /**
* 值减减操作,类似 --$i ,如果 key 不存在时自动设置为 0 后进行减减操作
*
* @param string $key 缓存KEY
* @param int $default 操作时的默认值
* @return int 操作后的值
*/
public function decr($key,$default=1){
if($default == 1){
return $this->getRedis()->decr($key);
}else{
return $this->getRedis()->decrBy($key, $default);
}
} /**
* 添空当前数据库
*
* @return boolean
*/
public function clear(){
if(!empty( $this->_linkHandle['master'])){
$this->_linkHandle['master']->flushDB();
}
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->flushDB();
}
return true;
} /* =================== 以下私有方法 =================== */ /**
* 随机 HASH 得到 Redis Slave 服务器句柄
*
* @return redis object
*/
private function _getSlaveRedis(){
// 就一台 Slave 机直接返回
if($this->_sn <= 1){
return $this->_linkHandle['slave'][0];
}
// 随机 Hash 得到 Slave 的句柄
$hash = $this->_hashId(mt_rand(), $this->_sn);
return $this->_linkHandle['slave'][$hash];
} /**
* 根据ID得到 hash 后 0~m-1 之间的值
*
* @param string $id
* @param int $m
* @return int
*/
private function _hashId($id,$m=10)
{
//把字符串K转换为 0~m-1 之间的一个值作为对应记录的散列地址
$k = md5($id);
$l = strlen($k);
$b = bin2hex($k);
$h = 0;
for($i=0;$i<$l;$i++)
{
//相加模式HASH
$h += substr($b,$i*2,2);
}
$hash = ($h*1)%$m;
return $hash;
} }// End Class class CRedisServerConfiguration extends CComponent
{
/**
* @var string memcache server hostname or IP address
*/
public $host;
/**
* @var integer memcache server port
*/
public $port=11211; public $master = false;
/**
* Constructor.
* @param array $config list of memcache server configurations.
* @throws CException if the configuration is not an array
*/
public function __construct($config)
{
if(is_array($config))
{
foreach($config as $key=>$value)
$this->$key=$value;
if($this->host===null)
throw new CException(Yii::t('yii','CMemCache server configuration must have "host" value.'));
}
else
throw new CException(Yii::t('yii','CMemCache server configuration must be an array.'));
}
}

Yii框架下使用redis做缓存,读写分离的更多相关文章

  1. yii框架下使用redis

    1 首先获取到 yii2-redis-master.zip 压缩包 下载地址https://github.com/yiisoft/yii2-redis/archive/master.zip 2 把下载 ...

  2. Yii框架 多数据库、主从、读写分离

    Yii是可以在配置文件里声明多个数据库连接,然后通过Yii::app()->db1,Yii::app()->db2...来访问它们,并且也实现了更高级(自动)的主从数据库功能. 最近因为一 ...

  3. spring+redis的集成,redis做缓存

    1.前言 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.我们都知道,在日常的应用中,数据库瓶颈是最容易出现的 ...

  4. SpringBoot之Mybatis操作中使用Redis做缓存

    上一博客学习了SpringBoot集成Redis,今天这篇博客学习下Mybatis操作中使用Redis做缓存.这里其实主要学习几个注解:@CachePut.@Cacheable.@CacheEvict ...

  5. 项目总结10:通过反射解决springboot环境下从redis取缓存进行转换时出现ClassCastException异常问题

    通过反射解决springboot环境下从redis取缓存进行转换时出现ClassCastException异常问题 关键字 springboot热部署  ClassCastException异常 反射 ...

  6. spring-boot集成mybatis,用redis做缓存

    网上有很多例子了,执行源码起码有3个,都是各种各样的小问题. 现在做了个小demo,实现spring-boot 用redis做缓存的实例,简单记录下思路,分享下源码. 缓存的实现,分担了数据库的压力, ...

  7. 如何用redis做缓存

    redis缓存 在互联网应用中经常需要用redis来缓存热点数据. redis数据在内存,可以保证数据读取的高效,接近每秒数十万次的吞吐量 减少下层持久层数据库读取压力,像mongodb,每秒近千次读 ...

  8. django使用redis做缓存

    Django 使用 Redis 做缓存 django中应用redis:pip3 install django-redis - 配置 CACHES = { "default": { ...

  9. Spring Boot 2整合Redis做缓存

    既然是要用Redis做缓存,自然少不了安装了.但是本文主要讲Spring Boot与Redis整合.安装教程请另行百度! 1.首先是我们的Redis配置类 package com.tyc; impor ...

随机推荐

  1. Linux性能实时监测工具 Netdata

    http://www.oschina.net/p/netdata?fromerr=hjJMgUjE#rd

  2. PAT 1006

    1006. Sign In and Sign Out (25) At the beginning of every day, the first person who signs in the com ...

  3. android startActivityForResult(Intent intent, int requestCode) 整理与总结! .

    假设有两个Activity,主界面A,功能界面B,由A启动B,并传数据给B,B在经过处理后把数据传回给A. 先是A传B: Bundle bundle = new Bundle();bundle.put ...

  4. JPA OpenJPA 简单例子

    JPA 全称,Java Persistence API,Java持久化API JPA是一套持久化标准,相当于JDBC标准,针对于此标准的实现目前有OpenJAP,TOPLINK,Hibernate等. ...

  5. HTML5中表单元素的formaction属性

    在submit按钮中,根据不同的submit按钮,将表单提交到不同的页面中: <form id="test" action="test.jsp"> ...

  6. 使用CompletionService结合ExecutorService批处理任务

    CompletionService用于提交一组Callable任务,其take方法返回已完成的一个Callable任务对应的Future对象. 如果你向Executor提交了一个批处理任务,并且希望在 ...

  7. 修改Atom 隐藏.gitignore忽略的文件/文件夹的配置

    参考链接:.gitignored files are hidden from tree view regardless of setting 假如Atom打开的文件夹有.gitignore 文件,会隐 ...

  8. CCLablettf读取显示xml文件内容显示中文

    CCDictionary *strings = CCDictionary::createWithContentsOfFile("tips2.xml"); const char *h ...

  9. 【Objective-C】2.自定义构造方法和description方法

    1.Student.h 1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject { 4 int _age ...

  10. http请求之referer头与防盗链

    在网页中的占用大流量的信息可以写成这个信息在网络上的url位置,这样就会减少本网站的流量,但是其他网站也 不会随意让你使用人家的资源,因为这样的情对人家的网站没有好处,会增加人家网站的流量,所以要防止 ...