Think/Db/Lite类 调整

This commit is contained in:
ThinkPHP
2013-04-27 21:18:14 +08:00
parent dc4ed37b4c
commit b89d2cba76

View File

@@ -1,411 +1,457 @@
<?php <?php
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | TOPThink [ WE CAN DO IT JUST THINK ] // | TOPThink [ WE CAN DO IT JUST THINK ]
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Copyright (c) 2011 http://topthink.com All rights reserved. // | Copyright (c) 2011 http://topthink.com All rights reserved.
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com> // | Author: liu21st <liu21st@gmail.com>
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace Think\Db; namespace Think\Db;
use Think\Config; use Think\Config;
use Think\Debug; use Think\Debug;
use Think\Log; use Think\Log;
use PDO; use PDO;
class Lite { class Lite {
// PDO操作实例 // PDO操作实例
protected $PDOStatement = null; protected $PDOStatement = null;
// 当前操作所属的模型名 // 当前操作所属的模型名
protected $model = '_think_'; protected $model = '_think_';
// 当前SQL指令 // 当前SQL指令
protected $queryStr = ''; protected $queryStr = '';
protected $modelSql = []; protected $modelSql = [];
// 最后插入ID // 最后插入ID
protected $lastInsID = null; protected $lastInsID = null;
// 返回或者影响记录数 // 返回或者影响记录数
protected $numRows = 0; protected $numRows = 0;
// 事务指令数 // 事务指令数
protected $transTimes = 0; protected $transTimes = 0;
// 错误信息 // 错误信息
protected $error = ''; protected $error = '';
// 数据库连接ID 支持多个连接 // 数据库连接ID 支持多个连接
protected $linkID = []; protected $linkID = [];
// 当前连接ID // 当前连接ID
protected $_linkID = null; protected $_linkID = null;
// 当前查询ID // 数据库连接参数配置
protected $queryID = null; protected $config = [
// 数据库连接参数配置 'type' => '', // 数据库类型
protected $config = []; 'hostname' => '127.0.0.1', // 服务器地址
'database' => '', // 数据库名
protected $queryTimes = 0; 'username' => '', // 用户名
protected $executeTimes = 0; 'password' => '', // 密码
// PDO连接参数 'hostport' => '', // 端口
protected $options = [ 'dsn' => '', //
PDO::ATTR_CASE => PDO::CASE_LOWER, 'params' => [], // 数据库连接参数
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, 'charset' => 'utf8', // 数据库编码默认采用utf8
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, 'prefix' => '', // 数据库表前缀
PDO::ATTR_STRINGIFY_FETCHES => false, 'debug' => false, // 数据库调试模式
]; 'deploy' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'rw_separate' => false, // 数据库读写是否分离 主从式有效
/** 'master_num' => 1, // 读写分离后 主服务器数量
* 架构函数 读取数据库配置信息 'slave_no' => '', // 指定从服务器序号
* @access public ];
* @param array $config 数据库配置数组 // 数据库表达式
*/ protected $comparison = ['eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN'];
public function __construct($config=''){ // 查询表达式
if(!empty($config)) { protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
$this->config = $config; // 查询次数
if(empty($this->config['params'])) { protected $queryTimes = 0;
$this->config['params'] = []; // 执行次数
} protected $executeTimes = 0;
$this->config['params'] = $this->options+$this->config['params']; // PDO连接参数
} protected $options = [
} PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
/** PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
* 连接数据库方法 PDO::ATTR_STRINGIFY_FETCHES => false,
* @access public ];
*/
public function connect($config='',$linkNum=0) { /**
if ( !isset($this->linkID[$linkNum]) ) { * 架构函数 读取数据库配置信息
if(empty($config)) $config = $this->config; * @access public
try{ * @param array $config 数据库配置数组
if(empty($config['dsn'])) { */
$config['dsn'] = $config['dbms'].':dbname='.$config['database'].';host='.$config['hostname']; public function __construct($config=''){
if(!empty($config['hostport'])) { if(!empty($config)) {
$config['dsn'] .= ';port='.$config['hostport']; $this->config = array_merge($this->config,$config);
}elseif(!empty($config['unix_socket'])){ $this->config['params'] = $this->options+$this->config['params'];
$config['dsn'] .= ';unix_socket='.$config['unix_socket']; }
} }
}
$this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); /**
}catch (\PDOException $e) { * 连接数据库方法
E($e->getMessage()); * @access public
} */
if(!empty($config['charset'])) { public function connect($config='',$linkNum=0) {
$this->linkID[$linkNum]->exec('SET NAMES '.$config['charset']); if ( !isset($this->linkID[$linkNum]) ) {
} if(empty($config)) $config = $this->config;
// 注销数据库连接配置信息 try{
if(1 != $config['deploy']) $this->config = []; if(empty($config['dsn'])) {
} $config['dsn'] = $this->parseDsn($config);
return $this->linkID[$linkNum]; }
} $this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']);
}catch (\PDOException $e) {
/** E($e->getMessage());
* 释放查询结果 }
* @access public }
*/ return $this->linkID[$linkNum];
public function free() { }
$this->PDOStatement = null;
} /**
* 解析pdo连接的dsn信息
/** * @access public
* 执行查询 返回数据集 * @param array $config 连接信息
* @access public * @return string
* @param string $str sql指令 */
* @return mixed protected function parseDsn($config){}
*/
public function query($str,$bind=[]) { /**
$this->initConnect(false); * 释放查询结果
if ( !$this->_linkID ) return false; * @access public
$this->queryStr = $str; */
//释放前次的查询结果 public function free() {
if ( !empty($this->PDOStatement) ) $this->free(); $this->PDOStatement = null;
$this->queryTimes++; }
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str); /**
if(false === $this->PDOStatement) * 执行查询 返回数据集
E($this->error()); * @access public
$result = $this->PDOStatement->execute($bind); * @param string $str sql指令
$this->debug(false); * @param array $bind 参数绑定
if ( false === $result ) { * @return mixed
$this->error(); */
return false; public function query($str,$bind=[]) {
} else { $this->initConnect(false);
return $this->getResult(); if ( !$this->_linkID ) return false;
} $this->queryStr = $str;
} if(!empty($bind)){
$this->queryStr .= '[ '.print_r($bind,true).' ]';
/** }
* 执行语句 //释放前次的查询结果
* @access public if ( !empty($this->PDOStatement) ) $this->free();
* @param string $str sql指令 $this->queryTimes++;
* @return integer // 调试开始
*/ $this->debug(true);
public function execute($str,$bind=[]) { $this->PDOStatement = $this->_linkID->prepare($str);
$this->initConnect(true); if(false === $this->PDOStatement)
if ( !$this->_linkID ) return false; E($this->error());
$this->queryStr = $str; foreach ($bind as $key => $val) {
//释放前次的查询结果 if(is_array($val)){
if ( !empty($this->PDOStatement) ) $this->free(); $this->PDOStatement->bindValue($key, $val[0], $val[1]);
$this->executeTimes++; }else{
// 记录开始执行时间 $this->PDOStatement->bindValue($key, $val);
$this->debug(true); }
$this->PDOStatement = $this->_linkID->prepare($str); }
if(false === $this->PDOStatement) { $result = $this->PDOStatement->execute();
E($this->error()); // 调试结束
} $this->debug(false);
$result = $this->PDOStatement->execute($bind); if ( false === $result ) {
$this->debug(false); $this->error();
if ( false === $result) { return false;
$this->error(); } else {
return false; return $this->getResult();
} else { }
$this->numRows = $this->PDOStatement->rowCount(); }
if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
$this->lastInsID = $this->getLastInsertId(); /**
} * 执行语句
return $this->numRows; * @access public
} * @param string $str sql指令
} * @param array $bind 参数绑定
* @return integer
/** */
* 获取最后插入id public function execute($str,$bind=[]) {
* @access public $this->initConnect(true);
* @return integer if ( !$this->_linkID ) return false;
*/ $this->queryStr = $str;
public function getLastInsertId() { if(!empty($bind)){
return $this->_linkID->lastInsertId(); $this->queryStr .= '[ '.print_r($bind,true).' ]';
} }
//释放前次的查询结果
/** if ( !empty($this->PDOStatement) ) $this->free();
* 启动事务 $this->executeTimes++;
* @access public // 记录开始执行时间
* @return void $this->debug(true);
*/ $this->PDOStatement = $this->_linkID->prepare($str);
public function startTrans() { if(false === $this->PDOStatement) {
$this->initConnect(true); E($this->error());
if ( !$this->_linkID ) return false; }
//数据rollback 支持 foreach ($bind as $key => $val) {
if ($this->transTimes == 0) { if(is_array($val)){
$this->_linkID->beginTransaction(); $this->PDOStatement->bindValue($key, $val[0], $val[1]);
} }else{
$this->transTimes++; $this->PDOStatement->bindValue($key, $val);
return ; }
} }
$result = $this->PDOStatement->execute();
/** $this->debug(false);
* 用于非自动提交状态下面的查询提交 if ( false === $result) {
* @access public $this->error();
* @return boolen return false;
*/ } else {
public function commit() { $this->numRows = $this->PDOStatement->rowCount();
if ($this->transTimes > 0) { if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
$result = $this->_linkID->commit(); $this->lastInsID = $this->_linkID->lastInsertId();
$this->transTimes = 0; }
if(!$result){ return $this->numRows;
$this->error(); }
return false; }
}
} /**
return true; * 启动事务
} * @access public
* @return void
/** */
* 事务回滚 public function startTrans() {
* @access public $this->initConnect(true);
* @return boolen if ( !$this->_linkID ) return false;
*/ //数据rollback 支持
public function rollback() { if ($this->transTimes == 0) {
if ($this->transTimes > 0) { $this->_linkID->beginTransaction();
$result = $this->_linkID->rollback(); }
$this->transTimes = 0; $this->transTimes++;
if(!$result){ return ;
$this->error(); }
return false;
} /**
} * 用于非自动提交状态下面的查询提交
return true; * @access public
} * @return boolen
*/
/** public function commit() {
* 获得所有的查询数据 if ($this->transTimes > 0) {
* @access private $result = $this->_linkID->commit();
* @return array $this->transTimes = 0;
*/ if(!$result){
private function getResult() { $this->error();
//返回数据集 return false;
$result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC); }
$this->numRows = count( $result ); }
return $result; return true;
} }
/** /**
* 获得查询次数 * 事务回滚
* @access public * @access public
* @param boolean $execute 是否包含所有查询 * @return boolen
* @return integer */
*/ public function rollback() {
public function getQueryTimes($execute=false){ if ($this->transTimes > 0) {
return $execute?$this->queryTimes+$this->executeTimes:$this->queryTimes; $result = $this->_linkID->rollback();
} $this->transTimes = 0;
if(!$result){
/** $this->error();
* 获得执行次数 return false;
* @access public }
* @return integer }
*/ return true;
public function getExecuteTimes(){ }
return $this->executeTimes;
} /**
* 获得所有的查询数据
/** * @access private
* 关闭数据库 * @return array
* @access public */
*/ private function getResult() {
public function close() { //返回数据集
$this->_linkID = null; $result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);
} $this->numRows = count( $result );
return $result;
/** }
* 数据库错误信息
* 并显示当前的SQL语句 /**
* @access public * 获得查询次数
* @return string * @access public
*/ * @param boolean $execute 是否包含所有查询
public function error() { * @return integer
if($this->PDOStatement) { */
$error = $this->PDOStatement->errorInfo(); public function getQueryTimes($execute=false){
$this->error = $error[1].':'.$error[2]; return $execute?$this->queryTimes+$this->executeTimes:$this->queryTimes;
}else{ }
$this->error = '';
} /**
if('' != $this->queryStr){ * 获得执行次数
$this->error .= "\n [ SQL语句 ] : ".$this->queryStr; * @access public
} * @return integer
Log::record($this->error,'ERR'); */
return $this->error; public function getExecuteTimes(){
} return $this->executeTimes;
}
/**
* 获取最近一次查询的sql语句 /**
* @param string $model 模型名 * 关闭数据库
* @access public * @access public
* @return string */
*/ public function close() {
public function getLastSql($model='') { $this->_linkID = null;
return $model?$this->modelSql[$model]:$this->queryStr; }
}
/**
/** * 数据库错误信息
* 获取最近插入的ID * 并显示当前的SQL语句
* @access public * @access public
* @return string * @return string
*/ */
public function getLastInsID() { public function error() {
return $this->lastInsID; if($this->PDOStatement) {
} $error = $this->PDOStatement->errorInfo();
$this->error = $error[1].':'.$error[2];
/** }else{
* 获取最近的错误信息 $this->error = '';
* @access public }
* @return string if('' != $this->queryStr){
*/ $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
public function getError() { }
return $this->error; // 记录错误日志
} Log::record($this->error,'ERR');
if($this->config['debug']) {// 开启数据库调试模式
/** E($this->error);
* 设置当前操作模型 }else{
* @access public return $this->error;
* @param string $model 模型名 }
* @return void }
*/
public function setModel($model){ /**
$this->model = $model; * 获取最近一次查询的sql语句
} * @param string $model 模型名
* @access public
/** * @return string
* 数据库调试 记录当前SQL */
* @access protected public function getLastSql($model='') {
* @param boolean $start 调试开始标记 true 开始 false 结束 return $model?$this->modelSql[$model]:$this->queryStr;
*/ }
protected function debug($start) {
if($this->config['debug']) {// 开启数据库调试模式 /**
if($start) { * 获取最近插入的ID
Debug::remark('queryStartTime','time'); * @access public
}else{ * @return string
$this->modelSql[$this->model] = $this->queryStr; */
$this->model = '_think_'; public function getLastInsID() {
// 记录操作结束时间 return $this->lastInsID;
Debug::remark('queryEndTime','time'); }
Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL');
} /**
} * 获取最近的错误信息
} * @access public
* @return string
/** */
* 初始化数据库连接 public function getError() {
* @access protected return $this->error;
* @param boolean $master 主服务器 }
* @return void
*/ /**
protected function initConnect($master=true) { * SQL指令安全过滤
if(1 == $this->config['deploy']) * @access public
// 采用分布式数据库 * @param string $str SQL字符串
$this->_linkID = $this->multiConnect($master); * @return string
else */
// 默认单数据库 public function escapeString($str) {
if ( !$this->_linkID ) $this->_linkID = $this->connect(); return addslashes($str);
} }
/** /**
* 连接分布式服务器 * 设置当前操作模型
* @access protected * @access public
* @param boolean $master 主服务器 * @param string $model 模型名
* @return void * @return void
*/ */
protected function multiConnect($master=false) { public function setModel($model){
static $_config = []; $this->model = $model;
if(empty($_config)) { }
// 缓存分布式数据库配置解析
foreach ($this->config as $key=>$val){ /**
$_config[$key] = explode(',',$val); * 数据库调试 记录当前SQL
} * @access protected
} * @param boolean $start 调试开始标记 true 开始 false 结束
// 数据库读写是否分离 */
if(Config::get('db_rw_separate')){ protected function debug($start) {
// 主从式采用读写分离 if($this->config['debug']) {// 开启数据库调试模式
if($master) if($start) {
// 主服务器写入 Debug::remark('queryStartTime','time');
$r = floor(mt_rand(0,Config::get('db_master_num')-1)); }else{
else{ $this->modelSql[$this->model] = $this->queryStr;
if(is_numeric(Config::get('db_slave_no'))) {// 指定服务器读 //$this->model = '_think_';
$r = Config::get('db_slave_no'); // 记录操作结束时间
}else{ Debug::remark('queryEndTime','time');
// 读操作连接从服务器 Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL');
$r = floor(mt_rand(Config::get('db_master_num'),count($_config['hostname'])-1)); // 每次随机连接的数据库 }
} }
} }
}else{
// 读写操作不区分服务器 /**
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 * 初始化数据库连接
} * @access protected
$db_config = [ * @param boolean $master 主服务器
'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], * @return void
'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], */
'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], protected function initConnect($master=true) {
'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], if(!empty($this->config['deploy']))
'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], // 采用分布式数据库
'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], $this->_linkID = $this->multiConnect($master);
'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], else
]; // 默认单数据库
return $this->connect($db_config,$r); if ( !$this->_linkID ) $this->_linkID = $this->connect();
} }
/** /**
* 析构方法 * 连接分布式服务器
* @access public * @access protected
*/ * @param boolean $master 主服务器
public function __destruct() { * @return void
// 释放查询 */
if ($this->queryID){ protected function multiConnect($master=false) {
$this->free(); static $_config = [];
} if(empty($_config)) {
// 关闭连接 // 缓存分布式数据库配置解析
$this->close(); $_config['username'] = explode(',',$$this->config['username']);
} $_config['password'] = explode(',',$$this->config['password']);
} $_config['hostname'] = explode(',',$$this->config['hostname']);
$_config['hostport'] = explode(',',$$this->config['hostport']);
$_config['database'] = explode(',',$$this->config['database']);
$_config['dsn'] = explode(',',$$this->config['dsn']);
}
// 数据库读写是否分离
if($this->config['rw_separate']){
// 主从式采用读写分离
if($master)
// 主服务器写入
$r = floor(mt_rand(0,$this->config['master_num']-1));
else{
if(is_numeric($this->config['slave_no'])) {// 指定服务器读
$r = $this->config['slave_no'];
}else{
// 读操作连接从服务器
$r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1)); // 每次随机连接的数据库
}
}
}else{
// 读写操作不区分服务器
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库
}
$db_config = [
'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
];
return $this->connect($db_config,$r);
}
/**
* 析构方法
* @access public
*/
public function __destruct() {
// 释放查询
if ($this->PDOStatement){
$this->free();
}
// 关闭连接
$this->close();
}
}