class model{
// 每个模型都可以有自己的 db、cache 服务器
//public $db_conf = array();
//public $cache_conf = array();
// 必须指定这三项
public $table; // 表名
public $pri = array(); // 主键字段,如 ('cid'), ('cid', 'id')
public $maxid; // 自增字段
// 避免重复链接
static $dbs = array();
static $caches = array();
private $unique = array(); // 防止重复查询
/**
* 创建一次 db/cache 对象
* @param string $var 只能是 db cache
* @return object
*/
function __get($var) {
switch ($var) {
case 'db':
return $this->db = $this->load_db();
case 'cache':
return $this->cache = $this->load_cache();
case 'db_conf':
return $this->db_conf = &$_ENV['_config']['db'];
case 'cache_conf':
return $this->cache_conf = &$_ENV['_config']['cache'];
default:
return $this->$var = core::model($var);
}
}
/**
* 未定义的模型方法抛出异常
* @param string $method 不存在的方法名
*/
function __call($method, $args) {
throw new Exception("方法 $method 不存在");
}
/**
* 加载 db 对象
* @return object
*/
public function load_db() {
$type = $this->db_conf['type'];
if(isset($this->db_conf['master'])) {
$m = $this->db_conf['master'];
$id = $type.'-'.$m['host'].'-'.$m['user'].'-'.$m['password'].'-'.$m['name'].'-'.$m['tablepre'];
}else{
$id = $type;
}
if(isset(self::$dbs[$id])) {
return self::$dbs[$id];
}else{
$db = 'db_'.$type;
self::$dbs[$id] = new $db($this->db_conf);
return self::$dbs[$id];
}
}
/**
* 加载 cache 对象
* @return object
*/
public function load_cache() {
$type = $this->cache_conf['type'];
if(isset($this->cache_conf[$type])) {
$c = $this->cache_conf[$type];
$id = $type.'-'.$c['host'].'-'.$c['port'];
}else{
$id = $type;
}
if(isset(self::$caches[$id])) {
return self::$caches[$id];
}else{
$cache = 'cache_'.$type;
self::$caches[$id] = new $cache($this->cache_conf);
return self::$caches[$id];
}
}
// +---------------------------------------------------------------
// | cache + db + 模型 封装方法,所有符合标准的表结构都可以使用以下方法
// +---------------------------------------------------------------
/**
* 创建一条数据
* @param array $data 数据 (注意:不要包含自增字段)
* @return boot
*/
public function create($data) {
// 如果没有自增字段,则不统计 count() maxid()
if(empty($this->maxid)) {
$key = $this->pri2key($data);
return $this->cache_db_set($key, $data);
}else{
// 注意:因为考虑了多种情况,更换顺序或简化代码会造成问题
$data[$this->maxid] = $this->maxid('+1');
$key = $this->pri2key($data);
$this->count('+1');
if($this->cache_db_set($key, $data)) {
return $data[$this->maxid];
}else{
$this->maxid('-1');
$this->count('-1');
return FALSE;
}
}
}
/**
* 写入一条数据
* @param array $key 键名数组
* @param array $data 数据
* @param int $life 缓存时间 (默认为永久)
* @return bool
*/
/*
此接口中的 $key 参数格式不同于 cache, db 中的 set()
例子:
$this->user->set(1, array('username'=>'2b', 'password'=>'123'));
$this->user->set(array(1, 2), array('username'=>'2b', 'password'=>'123'));
*/
public function set($key, $data, $life = 0) {
$key = $this->arr2key($key);
$this->unique[$key] = $data;
return $this->cache_db_set($key, $data, $life);
}
/**
* 读取一条数据 (简化数组, 如: read(1,2,3,4) 表示 get(array(1,2,3,4)) 最多支持4个参数)
* @param string $arg1-$arg4 参数1-参数4
* @return array
*/
public function read($arg1, $arg2 = FALSE, $arg3 = FALSE, $arg4 = FALSE) {
$arr = ($arg2 !== FALSE) ? $this->arg2arr($arg1, $arg2, $arg3, $arg4) : (array)$arg1;
return $this->get($arr);
}
/**
* 读取一条数据
* @param array $arr 键名数组 提示:主键一列:array(1) 主键多列:array(1, 2)
* @return array
*/
// 技巧:可以简写成 1 程序会自动转换成 array(1)
public function get($arr) {
$key = $this->arr2key($arr);
if(!isset($this->unique[$key])) {
$this->unique[$key] = $this->cache_db_get($key);
}
return $this->unique[$key];
}
/**
* 读取多条数据 (multi_get 简写成 mget)
* @param array $arr 多列键名数组 (提示: 主键一列时使用一维数组,主键多列时使用二维数组)
* @return array
*/
// 主键一列:mget(array(1, 2, 3));
// 主键多列:mget(array(array(1, 1), array(1, 2), array(1, 3)));
public function mget($arr) {
$data = array();
foreach($arr as $k=>&$key) {
$key = $this->arr2key($key);
if(isset($this->unique[$key])) {
$data[$key] = $this->unique[$key];
unset($arr[$k]);
}else{
$this->unique[$key] = $data[$key] = NULL; // 占位 保证返回数组顺序
}
}
$data2 = $this->cache_db_multi_get($arr);
return array_merge($data, $data2);
}
/**
* 更新一条数据
* @param array $data 数据 (必须包含主键)
* @param int $life 缓存时间 (默认为永久)
* @return bool
*/
public function update($data, $life = 0) {
$key = $this->pri2key($data);
$this->unique[$key] = $data;
return $this->cache_db_update($key, $data, $life);
}
/**
* 删除一条数据 (简化数组, 如: delete(1,2,3,4) 表示 del(array(1,2,3,4)) 最多支持4个参数)
* @param string $arg1-$arg4 参数1-参数4
* @return array
*/
public function delete($arg1, $arg2 = FALSE, $arg3 = FALSE, $arg4 = FALSE) {
$arr = ($arg2 !== FALSE) ? $this->arg2arr($arg1, $arg2, $arg3, $arg4) : (array)$arg1;
return $this->del($arr);
}
/**
* 删除一条数据
* @param string $arr 键名数组
* @return bool
*/
public function del($arr) {
$key = $this->arr2key($arr);
$ret = $this->cache_db_delete($key);
if($ret) {
unset($this->unique[$key]);
$this->count('-1');
}
return $ret;
}
/**
* cache+db 清空
* @return boot
*/
public function truncate() {
return $this->cache_db_truncate();
}
/**
* cache+db 读取/设置 表最大ID
* @param string $val 设置值 有三种情况 1.不填为读取(默认) 2.基础上增加 如:'+1' 3.设置指定值
* @return int 返回最大ID
*/
public function maxid($val = FALSE) {
return $this->cache_db_maxid($val);
}
/**
* cache+db 读取/设置 表的总行数
* @param string $val 设置值 如:count() 读取、 count(100) 设置为100、 count('+1') 设置加1、 count('-1') 设置减1
* @return int
*/
public function count($val = FALSE) {
return $this->cache_db_count($val);
}
/**
* 根据条件读取数据
* @param array $where 条件
* @param array $order 排序
* @param int $start 开始位置
* @param int $limit 读取几条
* @param int $life 二级缓存时间 (默认为永久)
* @return array
*/
public function find_fetch($where = array(), $order = array(), $start = 0, $limit = 0, $life = 0) {
return $this->cache_db_find_fetch($this->table, $this->pri, $where, $order, $start, $limit, $life);
}
/**
* 根据条件返回 key 数组
* @param array $where 条件
* @param array $order 排序
* @param int $start 开始位置
* @param int $limit 读取几条
* @param int $life 二级缓存时间 (默认为永久)
* @return array
*/
public function find_fetch_key($where = array(), $order = array(), $start = 0, $limit = 0, $life = 0) {
return $this->cache_db_find_fetch_key($this->table, $this->pri, $where, $order, $start, $limit, $life);
}
/**
* 根据条件批量更新数据 (不建议用来更新大量数据,太暴力了)
* @param array $where 条件
* @param array $lowprority 是否开启不锁定表
* @return int 返回影响的记录行数
*/
public function find_update($where, $data, $lowprority = FALSE) {
$this->unique = array();
if($this->cache_conf['enable']) {
$n = $this->find_count($where);
if($n > 2000) {
$this->cache->truncate($this->table);
}else{
$keys = $this->find_fetch_key($where);
foreach($keys as $key) {
$this->cache->delete($key);
}
}
}
return $this->db->find_update($this->table, $where, $data, $lowprority);
}
/**
* 根据条件批量删除数据 (不建议用来删除大量数据,太暴力了)
* @param array $where 条件
* @param array $lowprority 是否开启不锁定表
* @return int 返回影响的记录行数
*/
public function find_delete($where, $lowprority = FALSE) {
$this->unique = array();
if($this->cache_conf['enable']) {
$n = $this->find_count($where);
if($n > 2000) {
$this->cache->truncate($this->table);
}else{
$keys = $this->find_fetch_key($where);
foreach($keys as $key) {
$this->cache_db_delete($key);
}
}
}
$num = $this->db->find_delete($this->table, $where, $lowprority);
if(!empty($this->maxid) && $num > 0) {
$this->count('-'.$num);
}
return $num;
}
/**
* 准确获取最大ID (速度慢)
* @param string $key 键名
* @return int 返回ID
*/
public function find_maxid() {
return isset($this->maxid) ? $this->db->find_maxid($this->table.'-'.$this->maxid) : 0;
}
/**
* 准确获取总条数 (速度慢)
* @param array $where 条件
* @return int 返回条数
*/
public function find_count($where = array()) {
return $this->db->find_count($this->table, $where);
}
/**
* 创建索引
* @param array $index 键名数组 // array('uid'=>1, 'dateline'=>-1, 'unique'=>TRUE, 'dropDups'=>TRUE) 为了配合 mongodb 的索引才这样设计的
* @return boot 返回ID
*/
public function index_create($index) {
return $this->db->index_create($this->table, $index);
}
/**
* 删除索引
* @param array $index 键名数组
* @return boot 返回ID
*/
public function index_drop($index) {
return $this->db->index_drop($this->table, $index);
}
/**
* 主键 转 key
* @param array $arr 数组 (关联数组)
* @return string 返回标准KEY
*/
public function pri2key($arr) {
$s = $this->table;
foreach($this->pri as $v) {
$s .= "-$v-".$arr[$v];
}
return $s;
}
/**
* 数组 转 key
* @param array $arr 数组 (数字数组)
* @return string 返回标准KEY
*/
public function arr2key($arr) {
$arr = (array)$arr;
$s = $this->table;
foreach($this->pri as $k=>$v) {
if(!isset($arr[$k])) {
$err = array();
foreach($this->pri as $pk=>$pv) {
$var = isset($arr[$pk]) ? $arr[$pk] : 'null';
$err[] = "'$pv => $var";
}
throw new Exception('非法键名数组: array('.implode(', ', $err).');');
}
$s .= "-$v-".$arr[$k];
}
return $s;
}
/**
* 多参数 转 数组
* @param int $arg1-$arg4 参数1-参数4
* @return array
*/
public function arg2arr($arg1, $arg2, $arg3 = FALSE, $arg4 = FALSE) {
$arr = (array)$arg1;
array_push($arr, $arg2);
$arg3 !== FALSE && array_push($arr, $arg3);
$arg4 !== FALSE && array_push($arr, $arg4);
return $arr;
}
// +------------------------------------------------------------------------------
// | cache + db 封装方法 (启用cache时优先读缓存) 不推荐外部使用
// +------------------------------------------------------------------------------
/**
* cache+db 读取一条数据
* @param string $key 键名
* @return mixed
*/
public function cache_db_get($key) {
if($this->cache_conf['enable']) {
$data = $this->cache->get($key);
if(empty($data)) {
$data = $this->db->get($key);
$this->cache->set($key, $data);
}
return $data;
}else{
return $this->db->get($key);
}
}
/**
* cache+db 读取多条数据
* @param array $keys 键名数组
* @return array
*/
public function cache_db_multi_get($keys) {
if($this->cache_conf['enable']) {
$data = $this->cache->multi_get($keys);
if(empty($data)) {
$data = $this->db->multi_get($keys);
foreach((array)$data as $k=>$v) {
$this->cache->set($k, $v);
}
}else{
foreach($data as $k=>&$v) {
if($v === FALSE) { // 等于 FALSE 时表示缓存不存在
$v = $this->db->get($k);
$this->cache->set($k, $v);
}
}
}
return $data;
}else{
return $this->db->multi_get($keys);
}
}
/**
* cache+db 写入一条数据
* @param string $key 键名
* @param mixed $data 数据
* @param int $life 缓存时间 (默认为永久)
* @return boot
*/
public function cache_db_set($key, $data, $life = 0) {
$this->cache_conf['enable'] && $this->cache->set($key, $data, $life);
return $this->db->set($key, $data);
}
/**
* cache+db 更新一条数据
* @param string $key 键名
* @param array $data 数据
* @param int $life 缓存时间 (默认为永久)
* @return boot
*/
public function cache_db_update($key, $data, $life = 0) {
$this->cache_conf['enable'] && $this->cache->update($key, $data, $life);
return $this->db->update($key, $data);
}
/**
* cache+db 删除一条数据
* @param string $key 键名
* @return boot
*/
public function cache_db_delete($key) {
$this->cache_conf['enable'] && $this->cache->delete($key);
return $this->db->delete($key);
}
/**
* cache+db 清空数据
* @return boot
*/
public function cache_db_truncate() {
$this->cache_conf['enable'] && $this->cache->truncate($this->table);
return $this->db->truncate($this->table);
}
/**
* cache+db 读取/设置 表最大ID
* @param string $val 设置值 有三种情况 1.不填为读取(默认) 2.基础上增加 如:'+1' 3.设置指定值
* @return int 返回最大ID
*/
public function cache_db_maxid($val = FALSE) {
$key = $this->table.'-'.$this->maxid;
if($this->cache_conf['enable']) {
if($val === FALSE) {
$maxid = $this->cache->maxid($key, $val);
if(empty($maxid)) {
$maxid = $this->db->maxid($key, $val);
$this->cache->maxid($key, $maxid);
}
return $maxid;
}else{
$maxid = $this->db->maxid($key, $val);
return $this->cache->maxid($key, $maxid);
}
}else{
return $this->db->maxid($key, $val);
}
}
/**
* cache+db 读取/设置 表的总行数
* @param string $val 设置值 有四种情况 1.不填为读取(默认) 2.基础上增加 如:'+1' 3.基础上减少 如:'-1' 4.设置指定值
* @return int
*/
public function cache_db_count($val = FALSE) {
$key = $this->table;
if($this->cache_conf['enable']) {
if($val === FALSE) {
$rows = $this->cache->count($key, $val);
if(empty($rows)) {
$rows = $this->db->count($key, $val);
$this->cache->count($key, $rows);
}
return $rows;
}else{
$rows = $this->db->count($key, $val);
return $this->cache->count($key, $rows);
}
}else{
return $this->db->count($key, $val);
}
}
/**
* cache+db 根据条件读取数据
* @param string $table 表名
* @param array $pri 主键
* @param array $where 条件
* @param array $order 排序
* @param int $start 开始位置
* @param int $limit 读取几条
* @param int $life 二级缓存时间 (默认为永久)
* @return array
*/
public function cache_db_find_fetch($table, $pri, $where = array(), $order = array(), $start = 0, $limit = 0, $life = 0) {
// 如果是 mongodb 就直接取数据,不支持缓存
if($this->db_conf['type'] == 'mongodb') {
return $this->db->find_fetch($table, $pri, $where, $order, $start, $limit);
}else{
$keys = $this->cache_db_find_fetch_key($table, $pri, $where, $order, $start, $limit, $life);
return $this->cache_db_multi_get($keys);
}
}
/**
* cache+db 根据条件返回 key 数组
* @param string $table 表名
* @param array $pri 主键
* @param array $where 条件
* @param array $order 排序
* @param int $start 开始位置
* @param int $limit 读取几条
* @param int $life 二级缓存时间 (默认为永久)
* @return array
*/
public function cache_db_find_fetch_key($table, $pri, $where = array(), $order = array(), $start = 0, $limit = 0, $life = 0) {
if($this->cache_conf['enable'] && $this->cache_conf['l2_cache'] === 1) {
$key = $table.'_'.md5(serialize(array($pri, $where, $order, $start, $limit)));
$keys = $this->cache->l2_cache_get($key);
if(empty($keys)) {
$keys = $this->db->find_fetch_key($table, $pri, $where, $order, $start, $limit);
$this->cache->l2_cache_set($key, $keys, $life);
}
}else{
$keys = $this->db->find_fetch_key($table, $pri, $where, $order, $start, $limit);
}
return $keys;
}
}
Copyright © 2012-2025TWCMS使用及开发手册 Inc. 保留所有权利。Powered by TWCMS 2.0.3
页面耗时0.8584秒, 内存占用230.37 KB, 访问数据库22次, PHP版本php8.0.3nts, 已关闭缓存
合作伙伴:爱云源码 twcms模板 老郭博客CMS 今日上线通王CMS模板 网页版PbootCMS开发助手 郑州泰鼎展柜 TWCMS随机标签插件 郑州展柜厂 大城县岩棉管怎么样及主要特点 TWCMS模板「高端响应式百度色资讯新闻类主题」 TWCMS模板「高端响应式类日主题」 TWCMS模板「简洁纯净新闻博客资讯主题模板」 响应式手游下载类网站模板 twcms支持php7.1.9替换文件 郑州空调上门维修 TWCMS模板「简洁大气新闻主题模板」 爱云CMS教程网 {block:list和{block:global_cate调用文章分类栏目名和url 雄鹰工具箱 郑州公墓价格 郑州展柜设计 郑州泰鼎展柜 郑州展柜生产厂家 珠宝展柜 河南郑州电脑上门维修 郑州led拼接屏维修 LECMS使用及开发手册 LECMS模板「响应式IT热点资讯类网站(自适应手机端)」 洞悉职场动态 职场礼仪 twcms模板教程 twcms随机主题 冠县护栏板 lecms无人值守系统使用教程 九型人格测试 唐诗三百首全集 吾爱谜语网