[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)