|
@@ -106,8 +106,6 @@ abstract class Connection
|
|
|
'query' => '\\think\\db\\Query',
|
|
|
// 是否需要断线重连
|
|
|
'break_reconnect' => false,
|
|
|
- // 断线标识字符串
|
|
|
- 'break_match_str' => [],
|
|
|
];
|
|
|
|
|
|
// PDO连接参数
|
|
@@ -119,21 +117,6 @@ abstract class Connection
|
|
|
PDO::ATTR_EMULATE_PREPARES => false,
|
|
|
];
|
|
|
|
|
|
- // 服务器断线标识字符
|
|
|
- protected $breakMatchStr = [
|
|
|
- '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',
|
|
|
- 'failed with errno',
|
|
|
- ];
|
|
|
-
|
|
|
// 绑定参数
|
|
|
protected $bind = [];
|
|
|
|
|
@@ -210,9 +193,9 @@ abstract class Connection
|
|
|
{
|
|
|
if (!empty($this->builderClassName)) {
|
|
|
return $this->builderClassName;
|
|
|
+ } else {
|
|
|
+ return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type'));
|
|
|
}
|
|
|
-
|
|
|
- return $this->getConfig('builder') ?: '\\think\\db\\builder\\' . ucfirst($this->getConfig('type'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -368,8 +351,7 @@ abstract class Connection
|
|
|
|
|
|
if (!isset(self::$info[$schema])) {
|
|
|
// 读取缓存
|
|
|
- $cacheFile = Container::get('app')->getRuntimePath() . 'schema' . DIRECTORY_SEPARATOR . $schema . '.php';
|
|
|
-
|
|
|
+ $cacheFile = Container::get('app')->getRuntimePath() . 'schema/' . $schema . '.php';
|
|
|
if (!$this->config['debug'] && is_file($cacheFile)) {
|
|
|
$info = include $cacheFile;
|
|
|
} else {
|
|
@@ -383,7 +365,6 @@ abstract class Connection
|
|
|
// 记录字段类型
|
|
|
$type[$key] = $val['type'];
|
|
|
$bind[$key] = $this->getFieldBindType($val['type']);
|
|
|
-
|
|
|
if (!empty($val['primary'])) {
|
|
|
$pk[] = $key;
|
|
|
}
|
|
@@ -491,55 +472,49 @@ abstract class Connection
|
|
|
*/
|
|
|
public function connect(array $config = [], $linkNum = 0, $autoConnection = false)
|
|
|
{
|
|
|
- if (isset($this->links[$linkNum])) {
|
|
|
- return $this->links[$linkNum];
|
|
|
- }
|
|
|
-
|
|
|
- if (!$config) {
|
|
|
- $config = $this->config;
|
|
|
- } else {
|
|
|
- $config = array_merge($this->config, $config);
|
|
|
- }
|
|
|
-
|
|
|
- // 连接参数
|
|
|
- if (isset($config['params']) && is_array($config['params'])) {
|
|
|
- $params = $config['params'] + $this->params;
|
|
|
- } else {
|
|
|
- $params = $this->params;
|
|
|
- }
|
|
|
-
|
|
|
- // 记录当前字段属性大小写设置
|
|
|
- $this->attrCase = $params[PDO::ATTR_CASE];
|
|
|
-
|
|
|
- if (!empty($config['break_match_str'])) {
|
|
|
- $this->breakMatchStr = array_merge($this->breakMatchStr, (array) $config['break_match_str']);
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- if (empty($config['dsn'])) {
|
|
|
- $config['dsn'] = $this->parseDsn($config);
|
|
|
+ if (!isset($this->links[$linkNum])) {
|
|
|
+ if (!$config) {
|
|
|
+ $config = $this->config;
|
|
|
+ } else {
|
|
|
+ $config = array_merge($this->config, $config);
|
|
|
}
|
|
|
|
|
|
- if ($config['debug']) {
|
|
|
- $startTime = microtime(true);
|
|
|
+ // 连接参数
|
|
|
+ if (isset($config['params']) && is_array($config['params'])) {
|
|
|
+ $params = $config['params'] + $this->params;
|
|
|
+ } else {
|
|
|
+ $params = $this->params;
|
|
|
}
|
|
|
|
|
|
- $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);
|
|
|
+ // 记录当前字段属性大小写设置
|
|
|
+ $this->attrCase = $params[PDO::ATTR_CASE];
|
|
|
|
|
|
- if ($config['debug']) {
|
|
|
- // 记录数据库连接信息
|
|
|
- $this->log('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']);
|
|
|
- }
|
|
|
+ try {
|
|
|
+ if (empty($config['dsn'])) {
|
|
|
+ $config['dsn'] = $this->parseDsn($config);
|
|
|
+ }
|
|
|
|
|
|
- return $this->links[$linkNum];
|
|
|
- } catch (\PDOException $e) {
|
|
|
- if ($autoConnection) {
|
|
|
- $this->log($e->getMessage(), 'error');
|
|
|
- return $this->connect($autoConnection, $linkNum);
|
|
|
- } else {
|
|
|
- throw $e;
|
|
|
+ if ($config['debug']) {
|
|
|
+ $startTime = microtime(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);
|
|
|
+
|
|
|
+ if ($config['debug']) {
|
|
|
+ // 记录数据库连接信息
|
|
|
+ $this->log('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn']);
|
|
|
+ }
|
|
|
+ } catch (\PDOException $e) {
|
|
|
+ if ($autoConnection) {
|
|
|
+ $this->log($e->getMessage(), 'error');
|
|
|
+ return $this->connect($autoConnection, $linkNum);
|
|
|
+ } else {
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ return $this->links[$linkNum];
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -560,9 +535,9 @@ abstract class Connection
|
|
|
{
|
|
|
if (!$this->linkID) {
|
|
|
return false;
|
|
|
+ } else {
|
|
|
+ return $this->linkID;
|
|
|
}
|
|
|
-
|
|
|
- return $this->linkID;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -808,10 +783,11 @@ abstract class Connection
|
|
|
$pk = $query->getPk($options);
|
|
|
|
|
|
if (!empty($options['cache']) && true === $options['cache']['key'] && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
|
|
- $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
|
|
|
+ $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
|
|
}
|
|
|
|
|
|
- $data = $options['data'];
|
|
|
+ $data = $options['data'];
|
|
|
+ $result = false;
|
|
|
|
|
|
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
|
|
// 判断查询缓存
|
|
@@ -820,57 +796,55 @@ abstract class Connection
|
|
|
if (is_string($cache['key'])) {
|
|
|
$key = $cache['key'];
|
|
|
} elseif (!isset($key)) {
|
|
|
- $key = $this->getCacheKey($query, $data);
|
|
|
+ $key = $this->getCacheKey($data, $options, $query->getBind(false));
|
|
|
}
|
|
|
|
|
|
$result = Container::get('cache')->get($key);
|
|
|
-
|
|
|
- if (false !== $result) {
|
|
|
- return $result;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- if (is_string($pk) && !is_array($data)) {
|
|
|
- if (isset($key) && strpos($key, '|')) {
|
|
|
- list($a, $val) = explode('|', $key);
|
|
|
- $item[$pk] = $val;
|
|
|
- } else {
|
|
|
- $item[$pk] = $data;
|
|
|
+ if (false === $result) {
|
|
|
+ if (is_string($pk)) {
|
|
|
+ if (!is_array($data)) {
|
|
|
+ if (isset($key) && strpos($key, '|')) {
|
|
|
+ list($a, $val) = explode('|', $key);
|
|
|
+ $item[$pk] = $val;
|
|
|
+ } else {
|
|
|
+ $item[$pk] = $data;
|
|
|
+ }
|
|
|
+ $data = $item;
|
|
|
+ }
|
|
|
}
|
|
|
- $data = $item;
|
|
|
- }
|
|
|
-
|
|
|
- $query->setOption('data', $data);
|
|
|
- $query->setOption('limit', 1);
|
|
|
+ $query->setOption('data', $data);
|
|
|
+ $query->setOption('limit', 1);
|
|
|
|
|
|
- // 生成查询SQL
|
|
|
- $sql = $this->builder->select($query);
|
|
|
+ // 生成查询SQL
|
|
|
+ $sql = $this->builder->select($query);
|
|
|
|
|
|
- $bind = $query->getBind();
|
|
|
+ $bind = $query->getBind();
|
|
|
|
|
|
- if (!empty($options['fetch_sql'])) {
|
|
|
- // 获取实际执行的SQL语句
|
|
|
- return $this->getRealSql($sql, $bind);
|
|
|
- }
|
|
|
+ if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
+ return $this->getRealSql($sql, $bind);
|
|
|
+ }
|
|
|
|
|
|
- // 事件回调
|
|
|
- $result = $query->trigger('before_find');
|
|
|
+ // 事件回调
|
|
|
+ if ($result = $query->trigger('before_find')) {
|
|
|
+ } else {
|
|
|
+ // 执行查询
|
|
|
+ $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
|
|
|
|
|
|
- if (!$result) {
|
|
|
- // 执行查询
|
|
|
- $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
|
|
|
+ if ($resultSet instanceof \PDOStatement) {
|
|
|
+ // 返回PDOStatement对象
|
|
|
+ return $resultSet;
|
|
|
+ }
|
|
|
|
|
|
- if ($resultSet instanceof \PDOStatement) {
|
|
|
- // 返回PDOStatement对象
|
|
|
- return $resultSet;
|
|
|
+ $result = isset($resultSet[0]) ? $resultSet[0] : null;
|
|
|
}
|
|
|
|
|
|
- $result = isset($resultSet[0]) ? $resultSet[0] : null;
|
|
|
- }
|
|
|
-
|
|
|
- if (isset($cache) && $result) {
|
|
|
- // 缓存数据
|
|
|
- $this->cacheData($key, $result, $cache);
|
|
|
+ if (isset($cache) && $result) {
|
|
|
+ // 缓存数据
|
|
|
+ $this->cacheData($key, $result, $cache);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return $result;
|
|
@@ -911,41 +885,42 @@ abstract class Connection
|
|
|
public function select(Query $query)
|
|
|
{
|
|
|
// 分析查询表达式
|
|
|
- $options = $query->getOptions();
|
|
|
+ $options = $query->getOptions();
|
|
|
+ $resultSet = false;
|
|
|
|
|
|
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
|
|
- $resultSet = $this->getCacheData($query, $options['cache'], null, $key);
|
|
|
-
|
|
|
- if (false !== $resultSet) {
|
|
|
- return $resultSet;
|
|
|
- }
|
|
|
+ // 判断查询缓存
|
|
|
+ $cache = $options['cache'];
|
|
|
+ $key = is_string($cache['key']) ? $cache['key'] : md5(serialize($options) . serialize($query->getBind(false)));
|
|
|
+ $resultSet = Container::get('cache')->get($key);
|
|
|
}
|
|
|
|
|
|
- // 生成查询SQL
|
|
|
- $sql = $this->builder->select($query);
|
|
|
-
|
|
|
- $bind = $query->getBind();
|
|
|
+ if (false === $resultSet) {
|
|
|
+ // 生成查询SQL
|
|
|
+ $sql = $this->builder->select($query);
|
|
|
|
|
|
- if (!empty($options['fetch_sql'])) {
|
|
|
- // 获取实际执行的SQL语句
|
|
|
- return $this->getRealSql($sql, $bind);
|
|
|
- }
|
|
|
+ $bind = $query->getBind();
|
|
|
|
|
|
- $resultSet = $query->trigger('before_select');
|
|
|
+ if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
+ return $this->getRealSql($sql, $bind);
|
|
|
+ }
|
|
|
|
|
|
- if (!$resultSet) {
|
|
|
- // 执行查询操作
|
|
|
- $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
|
|
|
+ if ($resultSet = $query->trigger('before_select')) {
|
|
|
+ } else {
|
|
|
+ // 执行查询操作
|
|
|
+ $resultSet = $this->query($sql, $bind, $options['master'], $options['fetch_pdo']);
|
|
|
|
|
|
- if ($resultSet instanceof \PDOStatement) {
|
|
|
- // 返回PDOStatement对象
|
|
|
- return $resultSet;
|
|
|
+ if ($resultSet instanceof \PDOStatement) {
|
|
|
+ // 返回PDOStatement对象
|
|
|
+ return $resultSet;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (!empty($options['cache']) && false !== $resultSet) {
|
|
|
- // 缓存数据集
|
|
|
- $this->cacheData($key, $resultSet, $options['cache']);
|
|
|
+ if (isset($cache) && false !== $resultSet) {
|
|
|
+ // 缓存数据集
|
|
|
+ $this->cacheData($key, $resultSet, $cache);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return $resultSet;
|
|
@@ -1033,7 +1008,6 @@ abstract class Connection
|
|
|
foreach ($array as $item) {
|
|
|
$sql = $this->builder->insertAll($query, $item, $replace);
|
|
|
$bind = $query->getBind();
|
|
|
-
|
|
|
if (!empty($options['fetch_sql'])) {
|
|
|
$fetchSql[] = $this->getRealSql($sql, $bind);
|
|
|
} else {
|
|
@@ -1058,10 +1032,12 @@ abstract class Connection
|
|
|
$bind = $query->getBind();
|
|
|
|
|
|
if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
return $this->getRealSql($sql, $bind);
|
|
|
+ } else {
|
|
|
+ // 执行操作
|
|
|
+ return $this->execute($sql, $bind);
|
|
|
}
|
|
|
-
|
|
|
- return $this->execute($sql, $bind);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1078,6 +1054,7 @@ abstract class Connection
|
|
|
// 分析查询表达式
|
|
|
$options = $query->getOptions();
|
|
|
|
|
|
+ // 生成SQL语句
|
|
|
$table = $this->parseSqlTable($table);
|
|
|
|
|
|
$sql = $this->builder->selectInsert($query, $fields, $table);
|
|
@@ -1085,10 +1062,12 @@ abstract class Connection
|
|
|
$bind = $query->getBind();
|
|
|
|
|
|
if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
return $this->getRealSql($sql, $bind);
|
|
|
+ } else {
|
|
|
+ // 执行操作
|
|
|
+ return $this->execute($sql, $bind);
|
|
|
}
|
|
|
-
|
|
|
- return $this->execute($sql, $bind);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1115,7 +1094,7 @@ abstract class Connection
|
|
|
if (is_string($pk) && isset($data[$pk])) {
|
|
|
$where[$pk] = [$pk, '=', $data[$pk]];
|
|
|
if (!isset($key)) {
|
|
|
- $key = $this->getCacheKey($query, $data[$pk]);
|
|
|
+ $key = $this->getCacheKey($data[$pk], $options);
|
|
|
}
|
|
|
unset($data[$pk]);
|
|
|
} elseif (is_array($pk)) {
|
|
@@ -1139,7 +1118,7 @@ abstract class Connection
|
|
|
$query->setOption('where', ['AND' => $where]);
|
|
|
}
|
|
|
} elseif (!isset($key) && is_string($pk) && isset($options['where']['AND'][$pk])) {
|
|
|
- $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
|
|
|
+ $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
|
|
}
|
|
|
|
|
|
// 更新数据
|
|
@@ -1152,34 +1131,34 @@ abstract class Connection
|
|
|
if (!empty($options['fetch_sql'])) {
|
|
|
// 获取实际执行的SQL语句
|
|
|
return $this->getRealSql($sql, $bind);
|
|
|
- }
|
|
|
-
|
|
|
- // 检测缓存
|
|
|
- $cache = Container::get('cache');
|
|
|
+ } else {
|
|
|
+ // 检测缓存
|
|
|
+ $cache = Container::get('cache');
|
|
|
+
|
|
|
+ if (isset($key) && $cache->get($key)) {
|
|
|
+ // 删除缓存
|
|
|
+ $cache->rm($key);
|
|
|
+ } elseif (!empty($options['cache']['tag'])) {
|
|
|
+ $cache->clear($options['cache']['tag']);
|
|
|
+ }
|
|
|
|
|
|
- if (isset($key) && $cache->get($key)) {
|
|
|
- // 删除缓存
|
|
|
- $cache->rm($key);
|
|
|
- } elseif (!empty($options['cache']['tag'])) {
|
|
|
- $cache->clear($options['cache']['tag']);
|
|
|
- }
|
|
|
+ // 执行操作
|
|
|
+ $result = '' == $sql ? 0 : $this->execute($sql, $bind);
|
|
|
|
|
|
- // 执行操作
|
|
|
- $result = '' == $sql ? 0 : $this->execute($sql, $bind);
|
|
|
+ if ($result) {
|
|
|
+ if (is_string($pk) && isset($where[$pk])) {
|
|
|
+ $data[$pk] = $where[$pk];
|
|
|
+ } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {
|
|
|
+ list($a, $val) = explode('|', $key);
|
|
|
+ $data[$pk] = $val;
|
|
|
+ }
|
|
|
|
|
|
- if ($result) {
|
|
|
- if (is_string($pk) && isset($where[$pk])) {
|
|
|
- $data[$pk] = $where[$pk];
|
|
|
- } elseif (is_string($pk) && isset($key) && strpos($key, '|')) {
|
|
|
- list($a, $val) = explode('|', $key);
|
|
|
- $data[$pk] = $val;
|
|
|
+ $query->setOption('data', $data);
|
|
|
+ $query->trigger('after_update');
|
|
|
}
|
|
|
|
|
|
- $query->setOption('data', $data);
|
|
|
- $query->trigger('after_update');
|
|
|
+ return $result;
|
|
|
}
|
|
|
-
|
|
|
- return $result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1200,9 +1179,9 @@ abstract class Connection
|
|
|
if (isset($options['cache']) && is_string($options['cache']['key'])) {
|
|
|
$key = $options['cache']['key'];
|
|
|
} elseif (!is_null($data) && true !== $data && !is_array($data)) {
|
|
|
- $key = $this->getCacheKey($query, $data);
|
|
|
+ $key = $this->getCacheKey($data, $options);
|
|
|
} elseif (is_string($pk) && isset($options['where']['AND'][$pk])) {
|
|
|
- $key = $this->getCacheKey($query, $options['where']['AND'][$pk]);
|
|
|
+ $key = $this->getCacheKey($options['where']['AND'][$pk], $options);
|
|
|
}
|
|
|
|
|
|
if (true !== $data && empty($options['where'])) {
|
|
@@ -1260,44 +1239,50 @@ abstract class Connection
|
|
|
{
|
|
|
$options = $query->getOptions();
|
|
|
|
|
|
+ $result = false;
|
|
|
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
|
|
+ // 判断查询缓存
|
|
|
+ $cache = $options['cache'];
|
|
|
|
|
|
- $result = $this->getCacheData($query, $options['cache'], $field, $key);
|
|
|
-
|
|
|
- if (false !== $result) {
|
|
|
- return $result;
|
|
|
- }
|
|
|
+ $key = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($options) . serialize($query->getBind(false)));
|
|
|
+ $result = Container::get('cache')->get($key);
|
|
|
}
|
|
|
|
|
|
- if (isset($options['field'])) {
|
|
|
- $query->removeOption('field');
|
|
|
- }
|
|
|
+ if (false === $result) {
|
|
|
+ if (isset($options['field'])) {
|
|
|
+ $query->removeOption('field');
|
|
|
+ }
|
|
|
|
|
|
- if (is_string($field)) {
|
|
|
- $field = array_map('trim', explode(',', $field));
|
|
|
- }
|
|
|
+ if (is_string($field)) {
|
|
|
+ $field = array_map('trim', explode(',', $field));
|
|
|
+ }
|
|
|
|
|
|
- $query->setOption('field', $field);
|
|
|
- $query->setOption('limit', 1);
|
|
|
+ $query->setOption('field', $field);
|
|
|
+ $query->setOption('limit', 1);
|
|
|
+ // 生成查询SQL
|
|
|
+ $sql = $this->builder->select($query);
|
|
|
|
|
|
- // 生成查询SQL
|
|
|
- $sql = $this->builder->select($query);
|
|
|
+ $bind = $query->getBind();
|
|
|
|
|
|
- $bind = $query->getBind();
|
|
|
+ if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
+ return $this->getRealSql($sql, $bind);
|
|
|
+ }
|
|
|
|
|
|
- if (!empty($options['fetch_sql'])) {
|
|
|
- // 获取实际执行的SQL语句
|
|
|
- return $this->getRealSql($sql, $bind);
|
|
|
- }
|
|
|
+ // 执行查询操作
|
|
|
+ $pdo = $this->query($sql, $bind, $options['master'], true);
|
|
|
|
|
|
- // 执行查询操作
|
|
|
- $pdo = $this->query($sql, $bind, $options['master'], true);
|
|
|
+ if (is_string($pdo)) {
|
|
|
+ // 返回SQL语句
|
|
|
+ return $pdo;
|
|
|
+ }
|
|
|
|
|
|
- $result = $pdo->fetchColumn();
|
|
|
+ $result = $pdo->fetchColumn();
|
|
|
|
|
|
- if (isset($cache) && false !== $result) {
|
|
|
- // 缓存数据
|
|
|
- $this->cacheData($key, $result, $cache);
|
|
|
+ if (isset($cache) && false !== $result) {
|
|
|
+ // 缓存数据
|
|
|
+ $this->cacheData($key, $result, $cache);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return false !== $result ? $result : $default;
|
|
@@ -1330,83 +1315,82 @@ abstract class Connection
|
|
|
{
|
|
|
$options = $query->getOptions();
|
|
|
|
|
|
+ $result = false;
|
|
|
+
|
|
|
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
|
|
|
// 判断查询缓存
|
|
|
$cache = $options['cache'];
|
|
|
|
|
|
- $guid = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $field);
|
|
|
-
|
|
|
+ $guid = is_string($cache['key']) ? $cache['key'] : md5($field . serialize($options) . serialize($query->getBind(false)));
|
|
|
$result = Container::get('cache')->get($guid);
|
|
|
+ }
|
|
|
|
|
|
- if (false !== $result) {
|
|
|
- return $result;
|
|
|
+ if (false === $result) {
|
|
|
+ if (isset($options['field'])) {
|
|
|
+ $query->removeOption('field');
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (isset($options['field'])) {
|
|
|
- $query->removeOption('field');
|
|
|
- }
|
|
|
+ if (is_null($field)) {
|
|
|
+ $field = '*';
|
|
|
+ } elseif ($key && '*' != $field) {
|
|
|
+ $field = $key . ',' . $field;
|
|
|
+ }
|
|
|
|
|
|
- if (is_null($field)) {
|
|
|
- $field = '*';
|
|
|
- } elseif ($key && '*' != $field) {
|
|
|
- $field = $key . ',' . $field;
|
|
|
- }
|
|
|
+ if (is_string($field)) {
|
|
|
+ $field = array_map('trim', explode(',', $field));
|
|
|
+ }
|
|
|
|
|
|
- if (is_string($field)) {
|
|
|
- $field = array_map('trim', explode(',', $field));
|
|
|
- }
|
|
|
+ $query->setOption('field', $field);
|
|
|
|
|
|
- $query->setOption('field', $field);
|
|
|
+ // 生成查询SQL
|
|
|
+ $sql = $this->builder->select($query);
|
|
|
|
|
|
- // 生成查询SQL
|
|
|
- $sql = $this->builder->select($query);
|
|
|
+ $bind = $query->getBind();
|
|
|
|
|
|
- $bind = $query->getBind();
|
|
|
+ if (!empty($options['fetch_sql'])) {
|
|
|
+ // 获取实际执行的SQL语句
|
|
|
+ return $this->getRealSql($sql, $bind);
|
|
|
+ }
|
|
|
|
|
|
- if (!empty($options['fetch_sql'])) {
|
|
|
- // 获取实际执行的SQL语句
|
|
|
- return $this->getRealSql($sql, $bind);
|
|
|
- }
|
|
|
+ // 执行查询操作
|
|
|
+ $pdo = $this->query($sql, $bind, $options['master'], true);
|
|
|
|
|
|
- // 执行查询操作
|
|
|
- $pdo = $this->query($sql, $bind, $options['master'], true);
|
|
|
+ if (1 == $pdo->columnCount()) {
|
|
|
+ $result = $pdo->fetchAll(PDO::FETCH_COLUMN);
|
|
|
+ } else {
|
|
|
+ $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);
|
|
|
+
|
|
|
+ if ('*' == $field && $key) {
|
|
|
+ $result = array_column($resultSet, null, $key);
|
|
|
+ } elseif ($resultSet) {
|
|
|
+ $fields = array_keys($resultSet[0]);
|
|
|
+ $count = count($fields);
|
|
|
+ $key1 = array_shift($fields);
|
|
|
+ $key2 = $fields ? array_shift($fields) : '';
|
|
|
+ $key = $key ?: $key1;
|
|
|
+
|
|
|
+ if (strpos($key, '.')) {
|
|
|
+ list($alias, $key) = explode('.', $key);
|
|
|
+ }
|
|
|
|
|
|
- if (1 == $pdo->columnCount()) {
|
|
|
- $result = $pdo->fetchAll(PDO::FETCH_COLUMN);
|
|
|
- } else {
|
|
|
- $resultSet = $pdo->fetchAll(PDO::FETCH_ASSOC);
|
|
|
-
|
|
|
- if ('*' == $field && $key) {
|
|
|
- $result = array_column($resultSet, null, $key);
|
|
|
- } elseif ($resultSet) {
|
|
|
- $fields = array_keys($resultSet[0]);
|
|
|
- $count = count($fields);
|
|
|
- $key1 = array_shift($fields);
|
|
|
- $key2 = $fields ? array_shift($fields) : '';
|
|
|
- $key = $key ?: $key1;
|
|
|
-
|
|
|
- if (strpos($key, '.')) {
|
|
|
- list($alias, $key) = explode('.', $key);
|
|
|
- }
|
|
|
+ if (2 == $count) {
|
|
|
+ $column = $key2;
|
|
|
+ } elseif (1 == $count) {
|
|
|
+ $column = $key1;
|
|
|
+ } else {
|
|
|
+ $column = null;
|
|
|
+ }
|
|
|
|
|
|
- if (2 == $count) {
|
|
|
- $column = $key2;
|
|
|
- } elseif (1 == $count) {
|
|
|
- $column = $key1;
|
|
|
+ $result = array_column($resultSet, $column, $key);
|
|
|
} else {
|
|
|
- $column = null;
|
|
|
+ $result = [];
|
|
|
}
|
|
|
-
|
|
|
- $result = array_column($resultSet, $column, $key);
|
|
|
- } else {
|
|
|
- $result = [];
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (isset($cache) && isset($guid)) {
|
|
|
- // 缓存数据
|
|
|
- $this->cacheData($guid, $result, $cache);
|
|
|
+ if (isset($cache) && isset($guid)) {
|
|
|
+ // 缓存数据
|
|
|
+ $this->cacheData($guid, $result, $cache);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return $result;
|
|
@@ -1800,9 +1784,22 @@ abstract class Connection
|
|
|
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 ($this->breakMatchStr as $msg) {
|
|
|
+ foreach ($info as $msg) {
|
|
|
if (false !== stripos($error, $msg)) {
|
|
|
return true;
|
|
|
}
|
|
@@ -2050,29 +2047,14 @@ abstract class Connection
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 获取缓存数据
|
|
|
- * @access protected
|
|
|
- * @param Query $query 查询对象
|
|
|
- * @param mixed $cache 缓存设置
|
|
|
- * @param array $options 缓存
|
|
|
- * @return mixed
|
|
|
- */
|
|
|
- protected function getCacheData(Query $query, $cache, $data, &$key = null)
|
|
|
- {
|
|
|
- // 判断查询缓存
|
|
|
- $key = is_string($cache['key']) ? $cache['key'] : $this->getCacheKey($query, $data);
|
|
|
-
|
|
|
- return Container::get('cache')->get($key);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
* 生成缓存标识
|
|
|
* @access protected
|
|
|
- * @param Query $query 查询对象
|
|
|
* @param mixed $value 缓存数据
|
|
|
+ * @param array $options 缓存参数
|
|
|
+ * @param array $bind 绑定参数
|
|
|
* @return string
|
|
|
*/
|
|
|
- protected function getCacheKey(Query $query, $value)
|
|
|
+ protected function getCacheKey($value, $options, $bind = [])
|
|
|
{
|
|
|
if (is_scalar($value)) {
|
|
|
$data = $value;
|
|
@@ -2080,16 +2062,14 @@ abstract class Connection
|
|
|
$data = $value[2];
|
|
|
}
|
|
|
|
|
|
- $prefix = 'think:' . $this->getConfig('database') . '.';
|
|
|
-
|
|
|
if (isset($data)) {
|
|
|
- return $prefix . $query->getTable() . '|' . $data;
|
|
|
- }
|
|
|
-
|
|
|
- try {
|
|
|
- return md5($prefix . serialize($query->getOptions()) . serialize($query->getBind(false)));
|
|
|
- } catch (\Exception $e) {
|
|
|
- return;
|
|
|
+ return 'think:' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ return md5(serialize($options) . serialize($bind));
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|