[TOC]
* * * * *
#1 數據庫連接對象
>>數據庫連接對象表示特定配置的數據庫連接對象
>可以用來對整個數據庫進行操作
## 1 數據庫連接對象配置操作
### $db->getConfig()
>> 獲取數據庫連接的配置參數
~~~
public function getConfig($config = '')
{
return $config ? $this->config[$config] : $this->config;
}
~~~
### $db->setConfig()
>> 修改數據庫連接的配置參數
~~~
public function setConfig($config, $value = '')
{
if (is_array($config)) {
$this->config = array_merge($this->config, $config);
} else {
$this->config[$config] = $value;
}
}
~~~
## 2 數據庫連接初始化
### $db->initConnect()
>>初始化數據庫連接(單數據庫服務器)
~~~
protected function initConnect($master = true)
{
if (!empty($this->config['deploy'])) {
// 采用分布式數據庫
if ($master) {
if (!$this->linkWrite) {
$this->linkWrite = $this->multiConnect(true);
}
$this->linkID = $this->linkWrite;
} else {
if (!$this->linkRead) {
$this->linkRead = $this->multiConnect(false);
}
$this->linkID = $this->linkRead;
}
} elseif (!$this->linkID) {
// 默認單數據庫
$this->linkID = $this->connect();
}
}
~~~
### $db->multiConnect()
>>初始化數據庫連接(分布式數據庫服務器)
~~~
protected function multiConnect($master = false)
{
$_config = [];
// 分布式數據庫配置解析
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$_config[$name] = explode(',', $this->config[$name]);
}
// 主服務器序號
$m = floor(mt_rand(0, $this->config['master_num'] - 1));
if ($this->config['rw_separate']) {
// 主從式采用讀寫分離
if ($master) // 主服務器寫入
{
$r = $m;
} elseif (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));
}
$dbMaster = false;
if ($m != $r) {
$dbMaster = [];
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$dbMaster[$name] = isset($_config[$name][$m]) ? $_config[$name][$m] : $_config[$name][0];
}
}
$dbConfig = [];
foreach (['username', 'password', 'hostname', 'hostport', 'database', 'dsn', 'charset'] as $name) {
$dbConfig[$name] = isset($_config[$name][$r]) ? $_config[$name][$r] : $_config[$name][0];
}
return $this->connect($dbConfig, $r, $r == $m ? false : $dbMaster);
}
~~~
#2 數據庫操作
## 1 基本操作
### $db->query()
>>執行數據庫查詢操作
~~~
public function query($sql, $bind = [], $master = false, $class = false)
{
$this->initConnect($master);
if (!$this->linkID) {
return false;
}
// 根據參數綁定組裝最終的SQL語句
$this->queryStr = $this->getRealSql($sql, $bind);
//釋放前次的查詢結果
if (!empty($this->PDOStatement)) {
$this->free();
}
Db::$queryTimes++;
try {
// 調試開始
$this->debug(true);
// 預處理
$this->PDOStatement = $this->linkID->prepare($sql);
// 參數綁定
$this->bindValue($bind);
// 執行查詢
$result = $this->PDOStatement->execute();
// 調試結束
$this->debug(false);
$procedure = in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
return $this->getResult($class, $procedure);
} catch (\PDOException $e) {
throw new PDOException($e, $this->config, $this->queryStr);
}
}
~~~
### $db->execute()
>>執行數據庫操作
~~~
public function execute($sql, $bind = [])
{
$this->initConnect(true);
if (!$this->linkID) {
return false;
}
// 根據參數綁定組裝最終的SQL語句
$this->queryStr = $this->getRealSql($sql, $bind);
//釋放前次的查詢結果
if (!empty($this->PDOStatement)) {
$this->free();
}
Db::$executeTimes++;
try {
// 調試開始
$this->debug(true);
// 預處理
$this->PDOStatement = $this->linkID->prepare($sql);
// 參數綁定操作
$this->bindValue($bind);
// 執行語句
$result = $this->PDOStatement->execute();
// 調試結束
$this->debug(false);
$this->numRows = $this->PDOStatement->rowCount();
return $this->numRows;
} catch (\PDOException $e) {
throw new PDOException($e, $this->config, $this->queryStr);
}
}
~~~
## 2 事務操作
### $db->startTrans()
>>啟動事務
~~~
public function startTrans()
{
$this->initConnect(true);
if (!$this->linkID) {
return false;
}
++$this->transTimes;
if (1 == $this->transTimes) {
$this->linkID->beginTransaction();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
$this->linkID->exec(
$this->parseSavepoint('trans' . $this->transTimes)
);
}
}
~~~
### $db->commit()
>>事務操作提交
~~~
public function commit()
{
$this->initConnect(true);
if (1 == $this->transTimes) {
$this->linkID->commit();
}
--$this->transTimes;
}
~~~
### $db->rollback()
>>事務操作回滾
~~~
public function rollback()
{
$this->initConnect(true);
if (1 == $this->transTimes) {
$this->linkID->rollBack();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
$this->linkID->exec(
$this->parseSavepointRollBack('trans' . $this->transTimes)
);
}
$this->transTimes = max(0, $this->transTimes - 1);
}
~~~
### $db->transaction()
>>執行數據庫事務
~~~
public function transaction($callback)
{
$this->startTrans();
try {
$result = null;
if (is_callable($callback)) {
$result = call_user_func_array($callback, [$this]);
}
$this->commit();
return $result;
} catch (\Exception $e) {
$this->rollback();
throw $e;
} catch (\Throwable $e) {
$this->rollback();
throw $e;
}
}
~~~
#3 數據庫操作信息
## 3-1 SQL語句
### $db->bindValue()
>>sql語句參數綁定
~~~
protected function bindValue(array $bind = [])
{
foreach ($bind as $key => $val) {
// 占位符
$param = is_numeric($key) ? $key + 1 : ':' . $key;
if (is_array($val)) {
$result = $this->PDOStatement->bindValue($param, $val[0], $val[1]);
} else {
$result = $this->PDOStatement->bindValue($param, $val);
}
if (!$result) {
throw new BindParamException(
"Error occurred when binding parameters '{$param}'",
$this->config,
$this->queryStr,
$bind
);
}
}
}
~~~
### $db->getRealSql()
>> 獲取拼接后的SQL語句
~~~
public function getRealSql($sql, array $bind = [])
{
if ($bind) {
foreach ($bind as $key => $val) {
$value = is_array($val) ? $val[0] : $val;
$type = is_array($val) ? $val[1] : PDO::PARAM_STR;
if (PDO::PARAM_STR == $type) {
$value = $this->quote($value);
}
// 判斷占位符
$sql = is_numeric($key) ?
substr_replace($sql, $value, strpos($sql, '?'), 1) :
str_replace(
[':' . $key . ')', ':' . $key . ',', ':' . $key . ' '],
[$value . ')', $value . ',', $value . ' '],
$sql . ' ');
}
}
return $sql;
}
~~~
### $db->quote()
>> SQL語句安全過濾
~~~
public function quote($str, $master = true)
{
$this->initConnect($master);
return $this->linkID ? $this->linkID->quote($str) : $str;
}
~~~
## 3-2 數據庫操作運行信息
### $db->getQueryTimes()
>>獲取查詢次數
~~~
public function getQueryTimes($execute = false)
{
return $execute ? Db::$queryTimes + Db::$executeTimes : Db::$queryTimes;
}
~~~
### $db->getExecuteTimes()
>>獲取執行次數
~~~
public function getExecuteTimes()
{
return Db::$executeTimes;
}
~~~
### $db->getLastSql()
>> 獲取最近一次查詢的sql語句
~~~
public function getLastSql()
{
return $this->queryStr;
}
~~~
### $db->getLastInsID()
>> 獲取最近插入的ID
~~~
public function getLastInsID($sequence = null)
{
return $this->linkID->lastInsertId($sequence);
}
~~~
### $db->getNumRows()
>> 獲取影響的記錄數
~~~
public function getNumRows()
{
return $this->numRows;
}
~~~
### $db->getError()
>> 獲取最近的錯誤信息
~~~
public function getError()
{
if ($this->PDOStatement) {
$error = $this->PDOStatement->errorInfo();
$error = $error[1] . ':' . $error[2];
} else {
$error = '';
}
if ('' != $this->queryStr) {
$error .= "\n [ SQL語句 ] : " . $this->queryStr;
}
return $error;
}
~~~
# 4 攔截操作
### __call()
>> 調用Query的查詢方法
~~~
public function __call($method, $args)
{
if (!isset($this->query['database'])) {
$this->query['database'] = new Query($this);
}
return call_user_func_array([$this->query['database'], $method], $args);
}
~~~
- 框架簡介
- 簡介
- 框架目錄
- 根目錄
- 應用目錄
- 核心目錄
- 擴展目錄
- 其他目錄
- 框架流程
- 啟動流程
- 請求流程
- 響應流程
- 框架結構
- 應用組織
- 網絡請求
- 路由組織
- 數據驗證
- 數據模型(M)
- 數據庫連接(Connection)
- 數據庫(Db)
- 查詢構造(Builder)
- 數據庫查詢(Query)
- 模型(Model)
- 模板視圖(V)
- 視圖(View)
- 模板引擎(Think)
- 模板標簽庫(TagLib)
- 控制器(C)
- 網絡響應
- 配置與緩存
- 配置操作
- 緩存操作
- cookie與session
- Cookie操作
- Session操作
- 自動加載
- 鉤子注冊
- 文件上傳
- 分頁控制
- 控制臺
- 自動構建
- 日志異常調試
- 異常處理
- 代碼調試
- 日志記錄
- 框架使用
- 1 環境搭建(Server)
- 2 網絡請求(Request)
- 3 請求路由(Route)
- 4 響應輸出(Response)
- 5 業務處理(Controller)
- 6 數據存取(Model)
- 7 Web界面(View)