您的位置:首页 > 数据库 > Memcache

Redis、Memcached简单封装

2016-03-19 15:12 495 查看
很多项目中都会用到memcached、redis作缓存,一般我们获取数据都会优先从缓存获取数据,如果缓存中没有,再去读取数据库或者从其他方式获得相应的数据,处理之后返回同时种入缓存,那么很多时候代码便要重复这样一个判断逻辑,于是在这里,考虑了这么一种方式,简单地封装了一个缓存控制类,在从缓存读取数据的时候传入一个回调函数,如果缓存中不存在就执行回调函数,返回回调函数的结果,并自动将结果存入缓存。

首先定义缓存控制类的接口

interface Interface_Cache {

/**
* 获取当前缓存控制类实例,单例模式
*/
public static function getInstance();

/**
* 获取当前类中原生mc、redis对象
*/
public function query();

/**
* 读取配置设置缓存
* @param array $cache_config 缓存配置
* @param array $cache_params 缓存参数,构造key
* @param callable $func 回调函数,返回应当设置的值,返回值为null时,不设置缓存数据
*/
public function set(array $cache_config, array $cache_params, callable $func);

/**
* 优先从缓存读取数据,如果缓存中不存在,执行回调函数获得数据返回,同时将数据写入缓存
* @param array $cache_config 缓存配置
* @param array $cache_params 缓存参数,构造key
* @param callable $func 回调函数,返回查询的数据,返回值为null时,不写入缓存
*/
public function get(array $cache_config, array $cache_params, callable $func);

}
然后进行不同的实现
memcached

class Base_Mc implements Interface_Cache {
private $_mc = null;
private static $_instance = null;

private function __construct() {
$this->_mc = new Memcached();
$this->_mc->addServer('127.0.0.1', 11211);
}

public static function getInstance() {
if(is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}

public function query() {
return $this->_mc;
}

public function set(array $cache_config, array $cache_params, callable $func) {
$key = self::buildKey($cache_params, $cache_config['key']);
$expire = $cache_config['expire'];

$data = call_user_func($func);
if(is_null($data)) {
return false;
}
$expire += $expire == 0? 0: time();
return $this->_mc->set($key, $data, $expire);
}

public function get(array $cache_config, array $cache_params, callable $func) {
$key = self::buildKey($cache_params, $cache_config['key']);
$expire = $cache_config['expire'];

$data = null;
if(false === ($data = $this->_mc->get($key))) {
$data = call_user_func($func);
if(is_null($data)) {
return null;
}
$expire += $expire == 0? 0: time();
$this->_mc->set($key, $data, $expire);
}
return $data;
}

private static function buildKey(array $args, $format) {
$key = vsprintf($format, $args);
return $key;
}

public function __destruct() {
unset($this->_mc);
}
}

redis,这里采用字符串或哈希的结构设置缓存

class Base_Redis implements Interface_Cache {
private $_redis = null;
private static $_instance = null;

private function __construct() {
if(is_null($this->_redis)) {
$this->_redis = new Redis();
$this->_redis->connect('127.0.0.1', '6379', 3);
}
}

public static function getInstance() {
if(is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}

public function query() {
return $this->_redis;
}

public function set(array $cache_config, array $cache_params, callable $func) {
$key = self::buildKey($cache_params, $cache_config['key']);
$expire = $cache_config['expire'];

$type = null;
$data = call_user_func($func);
if(is_null($data)) {
return false;
}

if(is_string($data) || is_numeric($data)) {
$this->_redis->setex($key, $expire, $data);
} else if(is_array($data)) {
$this->_redis->hMset($key, $data);
$this->_redis->expire($key, $expire);
}
return true;
}

public function get(array $cache_config, array $cache_params, callable $func) {
$key = self::buildKey($cache_params, $cache_config['key']);
$expire = $cache_config['expire'];

$data = null;
$type = $this->_redis->type($key);
$data = $type == Redis::REDIS_HASH? $this->_redis->hGetAll($key): $this->_redis->get($key);
if(false === $data || empty($data)) {
$data = call_user_func($func);

if(is_null($data)) {
return null;
}

if(is_string($data) || is_numeric($data)) {
$this->_redis->setex($key, $expire, $data);
} else if(is_array($data)) {
$this->_redis->hMset($key, $data);
$this->_redis->expire($key, $expire);
}
}
return $data;
}

private static function buildKey(array $args, $format) {
$key = vsprintf($format, $args);
$key = str_replace('_', ':', $key);
return $key;
}

public function __destruct() {
$this->_redis->close();
unset($this->_redis);
}

}
示例代码

class UserModel {

public static function getUserInfoById($user_id) {
$params = ['userId' => $user_id ];
$mc = Base_Mc::getInstance();
$cache_config = Comm_Config::get('cache.user');
$info = $mc->get($cache_config, $params, function() use ($params){
$user_sql = Impl_User::getInstance();
$rs = $user_sql->auto()->buildQuery($params)->exec();
if(empty($rs[0])) {
return null;
}
return $rs[0][0];
});
return $info;
}
}

这样实现有一个好处就是能比较容易实现redis、memcached之间的自由切换,考虑用传入回调函数而不是sql语句的方式,一个是因为数据不一定来自数据库,或许来自其他公共的接口等,不是sql而是fsockopen、curl等等,这样能够保证更好的灵活性,其二是通过传sql返回的结果是没有经过相应处理的,适用的范围也相对受限制。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: