tp5原始碼分析之資料庫查詢
阿新 • • 發佈:2019-02-01
1 查詢物件
查詢物件(Query)實現基本的查詢操作
與模型不同的是,查詢物件是在資料庫的整體上進行操作,所以需要指定資料庫表
模型針對的資料庫中的某個資料表的操作。
2 查詢操作
2-1 增刪改查
$query->insert()
public function insert(array $data, $replace = false, $getLastInsID = false, $sequence = null)
{
// 分析查詢表示式
$options = $this->parseExpress();
// 生成SQL語句
$sql = $this ->builder()->insert($data, $options, $replace);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
}
// 執行操作
$result = $this->execute($sql, $bind);
if ($getLastInsID) {
$sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null);
return $this->getLastInsID($sequence);
}
return $result;
}
$query->insertAll()
public function insertAll(array $dataSet)
{
// 分析查詢表示式
$options = $this ->parseExpress();
if (!is_array(reset($dataSet))) {
return false;
}
// 生成SQL語句
$sql = $this->builder()->insertAll($dataSet, $options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
} else {
// 執行操作
return $this->execute($sql, $bind);
}
}
$query->selectInsert()
public function selectInsert($fields, $table)
{
// 分析查詢表示式
$options = $this->parseExpress();
// 生成SQL語句
$table = $this->parseSqlTable($table);
$sql = $this->builder()->selectInsert($fields, $table, $options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
} else {
// 執行操作
return $this->execute($sql, $bind);
}
}
$query->select()
public function select($data = null)
{
if ($data instanceof Query) {
return $data->select();
} elseif ($data instanceof \Closure) {
call_user_func_array($data, [ & $this]);
$data = null;
}
// 分析查詢表示式
$options = $this->parseExpress();
if (false === $data) {
// 用於子查詢 不查詢只返回SQL
$options['fetch_sql'] = true;
} elseif (!is_null($data)) {
// 主鍵條件分析
$this->parsePkWhere($data, $options);
}
$resultSet = false;
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
// 判斷查詢快取
$cache = $options['cache'];
unset($options['cache']);
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));
$resultSet = Cache::get($key);
}
if (!$resultSet) {
// 生成查詢SQL
$sql = $this->builder()->select($options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
}
// 執行查詢操作
$resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_class']);
if ($resultSet instanceof \PDOStatement) {
// 返回PDOStatement物件
return $resultSet;
}
if (isset($cache)) {
// 快取資料集
if (isset($cache['tag'])) {
Cache::tag($cache['tag'])->set($key, $resultSet, $cache['expire']);
} else {
Cache::set($key, $resultSet, $cache['expire']);
}
}
}
// 返回結果處理
if (count($resultSet) > 0) {
// 資料列表讀取後的處理
if (!empty($this->model)) {
// 生成模型物件
$model = $this->model;
foreach ($resultSet as $key => $result) {
/** @var Model $result */
$result = new $model($result);
$result->isUpdate(true);
// 關聯查詢
if (!empty($options['relation'])) {
$result->relationQuery($options['relation']);
}
$resultSet[$key] = $result;
}
if (!empty($options['with']) && $result instanceof Model) {
// 預載入
$resultSet = $result->eagerlyResultSet($resultSet, $options['with'], is_object($resultSet) ? get_class($resultSet) : '');
}
}
} elseif (!empty($options['fail'])) {
$this->throwNotFound($options);
}
return $resultSet;
}
$query->find()
public function find($data = null)
{
if ($data instanceof Query) {
return $data->find();
} elseif ($data instanceof \Closure) {
call_user_func_array($data, [ & $this]);
$data = null;
}
// 分析查詢表示式
$options = $this->parseExpress();
if (!is_null($data)) {
// AR模式分析主鍵條件
$this->parsePkWhere($data, $options);
}
$options['limit'] = 1;
$result = false;
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
// 判斷查詢快取
$cache = $options['cache'];
if (true === $cache['key'] && !is_null($data) && !is_array($data)) {
$key = 'think:' . $options['table'] . '|' . $data;
} else {
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));
}
$result = Cache::get($key);
}
if (!$result) {
// 生成查詢SQL
$sql = $this->builder()->select($options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
}
// 執行查詢
$result = $this->query($sql, $bind, $options['master'], $options['fetch_class']);
if ($result instanceof \PDOStatement) {
// 返回PDOStatement物件
return $result;
}
if (isset($cache)) {
// 快取資料
if (isset($cache['tag'])) {
Cache::tag($cache['tag'])->set($key, $result, $cache['expire']);
} else {
Cache::set($key, $result, $cache['expire']);
}
}
}
// 資料處理
if (!empty($result[0])) {
$data = $result[0];
if (!empty($this->model)) {
// 返回模型物件
$model = $this->model;
$data = new $model($data);
$data->isUpdate(true, isset($options['where']['AND']) ? $options['where']['AND'] : null);
if ($this->allowField) {
$data->allowField($this->allowField);
}
// 關聯查詢
if (!empty($options['relation'])) {
$data->relationQuery($options['relation']);
}
if (!empty($options['with'])) {
// 預載入
$data->eagerlyResult($data, $options['with'], is_object($result) ? get_class($result) : '');
}
}
} elseif (!empty($options['fail'])) {
$this->throwNotFound($options);
} else {
$data = null;
}
return $data;
}
$query->update()
public function update(array $data)
{
$options = $this->parseExpress();
$pk = $this->getPk($options);
if (isset($options['cache']) && is_string($options['cache'])) {
$key = $options['cache'];
}
if (empty($options['where'])) {
// 如果存在主鍵資料 則自動作為更新條件
if (is_string($pk) && isset($data[$pk])) {
$where[$pk] = $data[$pk];
if (!isset($key)) {
$key = 'think:' . $options['table'] . '|' . $data[$pk];
}
unset($data[$pk]);
} elseif (is_array($pk)) {
// 增加複合主鍵支援
foreach ($pk as $field) {
if (isset($data[$field])) {
$where[$field] = $data[$field];
} else {
// 如果缺少複合主鍵資料則不執行
throw new Exception('miss complex primary data');
}
unset($data[$field]);
}
}
if (!isset($where)) {
// 如果沒有任何更新條件則不執行
throw new Exception('miss update condition');
} else {
$options['where']['AND'] = $where;
}
} elseif (is_string($pk) && isset($options['where']['AND'][$pk]) && is_scalar($options['where']['AND'][$pk])) {
$key = 'think:' . $options['table'] . '|' . $options['where']['AND'][$pk];
}
// 生成UPDATE SQL語句
$sql = $this->builder()->update($data, $options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
} else {
// 檢測快取
if (isset($key) && Cache::get($key)) {
// 刪除快取
Cache::rm($key);
}
// 執行操作
return '' == $sql ? 0 : $this->execute($sql, $bind);
}
}
$query->delete()
public function delete($data = null)
{
// 分析查詢表示式
$options = $this->parseExpress();
if (isset($options['cache']) && is_string($options['cache'])) {
$key = $options['cache'];
}
if (!is_null($data) && true !== $data) {
if (!isset($key) && !is_array($data)) {
// 快取標識
$key = 'think:' . $options['table'] . '|' . $data;
}
// AR模式分析主鍵條件
$this->parsePkWhere($data, $options);
}
if (true !== $data && empty($options['where'])) {
// 如果條件為空 不進行刪除操作 除非設定 1=1
throw new Exception('delete without condition');
}
// 生成刪除SQL語句
$sql = $this->builder()->delete($options);
// 獲取引數繫結
$bind = $this->getBind();
if ($options['fetch_sql']) {
// 獲取實際執行的SQL語句
return $this->connection->getRealSql($sql, $bind);
}
// 檢測快取
if (isset($key) && Cache::get($key)) {
// 刪除快取
Cache::rm($key);
}
// 執行操作
return $this->execute($sql, $bind);
}
2-2 事務操作
$query->startTrans()
啟動事務
public function startTrans()
{
$this->connection->startTrans();
}
$query->commit()
提交事務
public function commit()
{
$this->connection->commit();
}
$query->transaction()
執行事務
public function transaction($callback)
{
return $this->connection->transaction($callback);
}
$query->rollback()
回滾事務
public function rollback()
{
$this->connection->rollback();
}
2-3 sql語句操作
$query->query()
呼叫聯結器的靜態query方法
public function query($sql, $bind = [], $master = false, $class = false)
{
return $this->connection->query($sql, $bind, $master, $class);
}
$query->execute()
呼叫聯結器的靜態query方法
public function execute($sql, $bind = [])
{
return $this->connection->execute($sql, $bind);
}