更新内核,API接口开发的一些尝试,后期会增加API接口开发这块

This commit is contained in:
2017-05-22 20:48:10 +08:00
parent a4d58f9f09
commit 426195eb90
47 changed files with 1339 additions and 513 deletions

View File

@@ -27,7 +27,7 @@ abstract class Builder
// SQL表达式
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
protected $insertSql = '%INSERT% INTO %TABLE% (%FIELD%) VALUES (%DATA%) %COMMENT%';
protected $insertAllSql = 'INSERT INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
protected $insertAllSql = '%INSERT% INTO %TABLE% (%FIELD%) %DATA% %COMMENT%';
protected $updateSql = 'UPDATE %TABLE% SET %SET% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
@@ -88,7 +88,7 @@ abstract class Builder
}
// 获取绑定信息
$bind = $this->query->getFieldsBind($options);
$bind = $this->query->getFieldsBind($options['table']);
if ('*' == $options['field']) {
$fields = array_keys($bind);
} else {
@@ -222,6 +222,14 @@ abstract class Builder
protected function parseWhere($where, $options)
{
$whereStr = $this->buildWhere($where, $options);
if (!empty($options['soft_delete'])) {
// 附加软删除条件
list($field, $condition) = $options['soft_delete'];
$binds = $this->query->getFieldsBind($options['table']);
$whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
$whereStr = $whereStr . $this->parseWhereItem($field, $condition, '', $options, $binds);
}
return empty($whereStr) ? '' : ' WHERE ' . $whereStr;
}
@@ -243,7 +251,7 @@ abstract class Builder
}
$whereStr = '';
$binds = $this->query->getFieldsBind($options);
$binds = $this->query->getFieldsBind($options['table']);
foreach ($where as $key => $val) {
$str = [];
foreach ($val as $field => $value) {
@@ -280,13 +288,7 @@ abstract class Builder
$whereStr .= empty($whereStr) ? substr(implode(' ', $str), strlen($key) + 1) : implode(' ', $str);
}
if (!empty($options['soft_delete'])) {
// 附加软删除条件
list($field, $condition) = $options['soft_delete'];
$whereStr = $whereStr ? '( ' . $whereStr . ' ) AND ' : '';
$whereStr = $whereStr . $this->parseWhereItem($field, $condition, '', $options, $binds);
}
return $whereStr;
}
@@ -346,9 +348,14 @@ abstract class Builder
$whereStr = '';
if (in_array($exp, ['=', '<>', '>', '>=', '<', '<='])) {
// 比较运算 及 模糊匹配
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);
// 比较运算
if ($value instanceof \Closure) {
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseClosure($value);
} else {
$whereStr .= $key . ' ' . $exp . ' ' . $this->parseValue($value, $field);
}
} elseif ('LIKE' == $exp || 'NOT LIKE' == $exp) {
// 模糊匹配
if (is_array($value)) {
foreach ($value as $item) {
$array[] = $key . ' ' . $exp . ' ' . $this->parseValue($item, $field);
@@ -712,13 +719,14 @@ abstract class Builder
* @access public
* @param array $dataSet 数据集
* @param array $options 表达式
* @param bool $replace 是否replace
* @return string
*/
public function insertAll($dataSet, $options)
public function insertAll($dataSet, $options, $replace = false)
{
// 获取合法的字段
if ('*' == $options['field']) {
$fields = array_keys($this->query->getFieldsType($options));
$fields = array_keys($this->query->getFieldsType($options['table']));
} else {
$fields = $options['field'];
}
@@ -747,8 +755,9 @@ abstract class Builder
}
$fields = array_map([$this, 'parseKey'], array_keys(reset($dataSet)));
$sql = str_replace(
['%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
['%INSERT%', '%TABLE%', '%FIELD%', '%DATA%', '%COMMENT%'],
[
$replace ? 'REPLACE' : 'INSERT',
$this->parseTable($options['table'], $options),
implode(' , ', $fields),
implode(' UNION ALL ', $values),

View File

@@ -56,8 +56,6 @@ abstract class Connection
protected $attrCase = PDO::CASE_LOWER;
// 监听回调
protected static $event = [];
// 查询对象
protected $query = [];
// 使用Builder类
protected $builder;
// 数据库连接参数配置
@@ -137,19 +135,14 @@ abstract class Connection
}
/**
* 创建指定模型的查询对象
* @access public
* @param string $model 模型类名称
* @param string $queryClass 查询对象类名
* 获取新的查询对象
* @access protected
* @return Query
*/
public function getQuery($model = 'db', $queryClass = '')
protected function getQuery()
{
if (!isset($this->query[$model])) {
$class = $queryClass ?: $this->config['query'];
$this->query[$model] = new $class($this, 'db' == $model ? '' : $model);
}
return $this->query[$model];
$class = $this->config['query'];
return new $class($this);
}
/**
@@ -340,13 +333,9 @@ abstract class Connection
/**
* 执行查询 返回数据集
* @access public
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param bool $master 是否在主服务器读操作
* @param bool $class 是否返回PDO对象
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param boolean $master 是否在主服务器读操作
* @param bool $master 是否在主服务器读操作
* @param bool $pdo 是否返回PDO对象
* @return mixed
* @throws BindParamException
@@ -393,10 +382,15 @@ abstract class Connection
// 返回结果集
return $this->getResult($pdo, $procedure);
} catch (\PDOException $e) {
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
if ($this->isBreak($e)) {
return $this->close()->query($sql, $bind, $master, $pdo);
}
throw new PDOException($e, $this->config, $this->getLastsql());
} catch (\ErrorException $e) {
if ($this->isBreak($e)) {
return $this->close()->query($sql, $bind, $master, $pdo);
}
throw $e;
}
}
@@ -451,10 +445,15 @@ abstract class Connection
$this->numRows = $this->PDOStatement->rowCount();
return $this->numRows;
} catch (\PDOException $e) {
if ($this->config['break_reconnect'] && $this->isBreak($e)) {
if ($this->isBreak($e)) {
return $this->close()->execute($sql, $bind);
}
throw new PDOException($e, $this->config, $this->getLastsql());
} catch (\ErrorException $e) {
if ($this->isBreak($e)) {
return $this->close()->execute($sql, $bind);
}
throw $e;
}
}
@@ -629,13 +628,25 @@ abstract class Connection
}
++$this->transTimes;
try {
if (1 == $this->transTimes) {
$this->linkID->beginTransaction();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
$this->linkID->exec(
$this->parseSavepoint('trans' . $this->transTimes)
);
}
if (1 == $this->transTimes) {
$this->linkID->beginTransaction();
} elseif ($this->transTimes > 1 && $this->supportSavepoint()) {
$this->linkID->exec(
$this->parseSavepoint('trans' . $this->transTimes)
);
} catch (\PDOException $e) {
if ($this->isBreak($e)) {
return $this->close()->startTrans();
}
throw $e;
} catch (\ErrorException $e) {
if ($this->isBreak($e)) {
return $this->close()->startTrans();
}
throw $e;
}
}
@@ -771,11 +782,35 @@ abstract class Connection
/**
* 是否断线
* @access protected
* @param \PDOException $e 异常
* @param \PDOException $e 异常对象
* @return bool
*/
protected function isBreak($e)
{
if (!$this->config['break_reconnect']) {
return false;
}
$info = [
'server has gone away',
'no connection to the server',
'Lost connection',
'is dead or not enabled',
'Error while sending',
'decryption failed or bad record mac',
'server closed the connection unexpectedly',
'SSL connection has been closed unexpectedly',
'Error writing data to the connection',
'Resource deadlock avoided',
];
$error = $e->getMessage();
foreach ($info as $msg) {
if (false !== stripos($error, $msg)) {
return true;
}
}
return false;
}
@@ -860,7 +895,6 @@ abstract class Connection
Debug::remark('queryEndTime', 'time');
$runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime');
$sql = $sql ?: $this->getLastsql();
$log = $sql . ' [ RunTime:' . $runtime . 's ]';
$result = [];
// SQL性能分析
if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) {
@@ -918,7 +952,7 @@ abstract class Connection
{
if (!empty($this->config['deploy'])) {
// 采用分布式数据库
if ($master) {
if ($master || $this->transTimes) {
if (!$this->linkWrite) {
$this->linkWrite = $this->multiConnect(true);
}

View File

@@ -401,7 +401,7 @@ class Query
if (empty($this->options['table'])) {
$this->options['table'] = $this->getTable();
}
$key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options));
$key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
$result = Cache::get($key);
}
if (false === $result) {
@@ -444,14 +444,16 @@ class Query
if (empty($this->options['table'])) {
$this->options['table'] = $this->getTable();
}
$guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options));
$guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($this->options) . serialize($this->bind));
$result = Cache::get($guid);
}
if (false === $result) {
if (isset($this->options['field'])) {
unset($this->options['field']);
}
if ($key && '*' != $field) {
if (is_null($field)) {
$field = '*';
} elseif ($key && '*' != $field) {
$field = $key . ',' . $field;
}
$pdo = $this->field($field)->getPdo();
@@ -594,7 +596,7 @@ class Query
}
if ($lazyTime > 0) {
// 延迟写入
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition));
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));
$step = $this->lazyWrite('inc', $guid, $step, $lazyTime);
if (false === $step) {
// 清空查询条件
@@ -623,7 +625,7 @@ class Query
}
if ($lazyTime > 0) {
// 延迟写入
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition));
$guid = md5($this->getTable() . '_' . $field . '_' . serialize($condition) . serialize($this->bind));
$step = $this->lazyWrite('dec', $guid, $step, $lazyTime);
if (false === $step) {
// 清空查询条件
@@ -649,16 +651,16 @@ class Query
if (!Cache::has($guid . '_time')) {
// 计时开始
Cache::set($guid . '_time', $_SERVER['REQUEST_TIME'], 0);
Cache::$type($guid, $step, 0);
Cache::$type($guid, $step);
} elseif ($_SERVER['REQUEST_TIME'] > Cache::get($guid . '_time') + $lazyTime) {
// 删除缓存
$value = Cache::$type($guid, $step, 0);
$value = Cache::$type($guid, $step);
Cache::rm($guid);
Cache::rm($guid . '_time');
return 0 === $value ? false : $value;
} else {
// 更新缓存
Cache::$type($guid, $step, 0);
Cache::$type($guid, $step);
}
return false;
}
@@ -1132,6 +1134,7 @@ class Query
if ($field) {
$this->options['soft_delete'] = [$field, $condition ?: ['null', '']];
}
return $this;
}
/**
@@ -1773,21 +1776,21 @@ class Query
}
// 获取当前数据表字段信息
public function getTableFields($options)
public function getTableFields($table = '')
{
return $this->getTableInfo($options['table'], 'fields');
return $this->getTableInfo($table ?: $this->getOptions('table'), 'fields');
}
// 获取当前数据表字段类型
public function getFieldsType($options)
public function getFieldsType($table = '')
{
return $this->getTableInfo($options['table'], 'type');
return $this->getTableInfo($table ?: $this->getOptions('table'), 'type');
}
// 获取当前数据表绑定信息
public function getFieldsBind($options)
public function getFieldsBind($table = '')
{
$types = $this->getFieldsType($options);
$types = $this->getFieldsType($table);
$bind = [];
if ($types) {
foreach ($types as $key => $type) {
@@ -1900,6 +1903,9 @@ class Query
$closure = $relation;
$relation = $key;
$with[$key] = $key;
} elseif (is_array($relation)) {
$subRelation = $relation;
$relation = $key;
} elseif (is_string($relation) && strpos($relation, '.')) {
$with[$key] = $relation;
list($relation, $subRelation) = explode('.', $relation, 2);
@@ -1909,7 +1915,7 @@ class Query
$relation = Loader::parseName($relation, 1, false);
$model = $class->$relation();
if ($model instanceof OneToOne && 0 == $model->getEagerlyType()) {
$model->removeOption()->eagerly($this, $relation, $subRelation, $closure, $first);
$model->eagerly($this, $relation, $subRelation, $closure, $first);
$first = false;
} elseif ($closure) {
$with[$key] = $closure;
@@ -1997,7 +2003,7 @@ class Query
$relation = explode(',', $relation);
}
if (isset($this->options['relation'])) {
$this->options['relation'] = array_mrege($this->options['relation'], $relation);
$this->options['relation'] = array_merge($this->options['relation'], $relation);
} else {
$this->options['relation'] = $relation;
}
@@ -2111,9 +2117,10 @@ class Query
* 批量插入记录
* @access public
* @param mixed $dataSet 数据集
* @param boolean $replace 是否replace
* @return integer|string
*/
public function insertAll(array $dataSet)
public function insertAll(array $dataSet, $replace = false)
{
// 分析查询表达式
$options = $this->parseExpress();
@@ -2121,7 +2128,7 @@ class Query
return false;
}
// 生成SQL语句
$sql = $this->builder->insertAll($dataSet, $options);
$sql = $this->builder->insertAll($dataSet, $options, $replace);
// 获取参数绑定
$bind = $this->getBind();
if ($options['fetch_sql']) {
@@ -2203,7 +2210,7 @@ class Query
$options['where']['AND'] = $where;
}
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
}
// 生成UPDATE SQL语句
@@ -2291,7 +2298,7 @@ class Query
// 判断查询缓存
$cache = $options['cache'];
unset($options['cache']);
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options));
$key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($this->bind));
$resultSet = Cache::get($key);
}
if (!$resultSet) {
@@ -2383,8 +2390,9 @@ class Query
* @access public
* @param mixed $value 缓存数据
* @param array $options 缓存参数
* @param array $bind 绑定参数
*/
protected function getCacheKey($value, $options)
protected function getCacheKey($value, $options, $bind = [])
{
if (is_scalar($value)) {
$data = $value;
@@ -2392,9 +2400,9 @@ class Query
$data = $value[1];
}
if (isset($data)) {
return 'think:' . $options['table'] . '|' . $data;
return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
} else {
return md5(serialize($options));
return md5(serialize($options) . serialize($bind));
}
}
@@ -2422,7 +2430,7 @@ class Query
// AR模式分析主键条件
$this->parsePkWhere($data, $options);
} elseif (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
}
$options['limit'] = 1;
@@ -2435,7 +2443,7 @@ class Query
} elseif (is_string($cache['key'])) {
$key = $cache['key'];
} elseif (!isset($key)) {
$key = md5(serialize($options));
$key = md5(serialize($options) . serialize($this->bind));
}
$result = Cache::get($key);
}
@@ -2646,7 +2654,7 @@ class Query
// AR模式分析主键条件
$this->parsePkWhere($data, $options);
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
$key = $this->getCacheKey($options['where']['AND'][$pk], $options);
$key = $this->getCacheKey($options['where']['AND'][$pk], $options, $this->bind);
}
if (true !== $data && empty($options['where'])) {

View File

@@ -47,6 +47,9 @@ class Mysql extends Builder
$key = '`' . $key . '`';
}
if (isset($table)) {
if (strpos($table, '.')) {
$table = str_replace('.', '`.`', $table);
}
$key = '`' . $table . '`.' . $key;
}
return $key;

View File

@@ -21,7 +21,7 @@ class Sqlsrv extends Builder
protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';
protected $selectInsertSql = 'SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%';
protected $updateSql = 'UPDATE %TABLE% SET %SET% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
protected $deleteSql = 'DELETE FROM %TABLE% %USING% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
protected $deleteSql = 'DELETE FROM %TABLE% %USING% FROM %TABLE% %JOIN% %WHERE% %LIMIT% %LOCK%%COMMENT%';
/**
* order分析

View File

@@ -51,7 +51,7 @@ class Mysql extends Connection
*/
public function getFields($tableName)
{
$this->initConnect(true);
$this->initConnect(false);
list($tableName) = explode(' ', $tableName);
if (false === strpos($tableName, '`')) {
if (strpos($tableName, '.')) {
@@ -91,7 +91,7 @@ class Mysql extends Connection
*/
public function getTables($dbName = '')
{
$this->initConnect(true);
$this->initConnect(false);
$sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES ';
// 调试开始
$this->debug(true);
@@ -130,17 +130,4 @@ class Mysql extends Connection
return true;
}
/**
* 是否断线
* @access protected
* @param \PDOException $e 异常对象
* @return bool
*/
protected function isBreak($e)
{
if (false !== stripos($e->getMessage(), 'server has gone away')) {
return true;
}
return false;
}
}

View File

@@ -44,7 +44,7 @@ class Pgsql extends Connection
*/
public function getFields($tableName)
{
$this->initConnect(true);
$this->initConnect(false);
list($tableName) = explode(' ', $tableName);
$sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');';
// 调试开始
@@ -78,7 +78,7 @@ class Pgsql extends Connection
*/
public function getTables($dbName = '')
{
$this->initConnect(true);
$this->initConnect(false);
$sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'";
// 调试开始
$this->debug(true);

View File

@@ -42,7 +42,7 @@ class Sqlite extends Connection
*/
public function getFields($tableName)
{
$this->initConnect(true);
$this->initConnect(false);
list($tableName) = explode(' ', $tableName);
$sql = 'PRAGMA table_info( ' . $tableName . ' )';
// 调试开始
@@ -76,7 +76,7 @@ class Sqlite extends Connection
*/
public function getTables($dbName = '')
{
$this->initConnect(true);
$this->initConnect(false);
$sql = "SELECT name FROM sqlite_master WHERE type='table' "
. "UNION ALL SELECT name FROM sqlite_temp_master "
. "WHERE type='table' ORDER BY name";

View File

@@ -49,7 +49,7 @@ class Sqlsrv extends Connection
*/
public function getFields($tableName)
{
$this->initConnect(true);
$this->initConnect(false);
list($tableName) = explode(' ', $tableName);
$sql = "SELECT column_name, data_type, column_default, is_nullable
FROM information_schema.tables AS t
@@ -99,7 +99,7 @@ class Sqlsrv extends Connection
*/
public function getTables($dbName = '')
{
$this->initConnect(true);
$this->initConnect(false);
$sql = "SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'