实现请求缓存1天。

This commit is contained in:
2025-04-18 15:38:58 +08:00
parent 2d3f7d8511
commit 96da83a1ab
209 changed files with 19400 additions and 1657 deletions

View File

@@ -52,12 +52,6 @@ class DbManager
*/
protected $listen = [];
/**
* SQL日志
* @var array
*/
protected $dbLog = [];
/**
* 查询次数
* @var int
@@ -167,8 +161,6 @@ class DbManager
{
if ($this->log) {
$this->log->log($type, $log);
} else {
$this->dbLog[$type][] = $log;
}
}
@@ -180,12 +172,7 @@ class DbManager
*/
public function getDbLog(bool $clear = false): array
{
$logs = $this->dbLog;
if ($clear) {
$this->dbLog = [];
}
return $logs;
return [];
}
/**
@@ -292,16 +279,17 @@ class DbManager
/**
* 更新查询次数
* @deprecated
* @access public
* @return void
*/
public function updateQueryTimes(): void
{
$this->queryTimes++;
}
/**
* 重置查询次数
* @deprecated
* @access public
* @return void
*/
@@ -312,6 +300,7 @@ class DbManager
/**
* 获得查询次数
* @deprecated
* @access public
* @return integer
*/
@@ -340,7 +329,7 @@ class DbManager
{
return $this->listen;
}
/**
* 获取所有连接实列
* @access public

View File

@@ -121,6 +121,12 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
*/
private $lazySave = false;
/**
* 缓存自动更新标识
* @var bool|string
*/
protected $cacheKey = false;
/**
* Db对象
* @var DbManager
@@ -335,6 +341,18 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
return $this;
}
/**
* 设置当前查询的自动缓存标识
* @access public
* @param string|bool $key 缓存标识
* @return $this
*/
public function setCacheKey($key)
{
$this->cacheKey = $key;
return $this;
}
/**
* 获取当前模型的数据表后缀
* @access public
@@ -641,7 +659,7 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$result = $db->where($where)
->strict(false)
->cache(true)
->cache($this->cacheKey)
->setOption('key', $this->key)
->field($allowFields)
->update($data);
@@ -769,16 +787,20 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$pk = $this->getPk();
if (is_string($pk) && $replace) {
$auto = true;
}
$result = [];
$suffix = $this->getSuffix();
foreach ($dataSet as $key => $data) {
if ($this->exists || (!empty($auto) && isset($data[$pk]))) {
if ($replace) {
$exists = true;
foreach ((array) $pk as $field) {
if (!isset($data[$field])) {
$exists = false;
}
}
}
if ($replace && !empty($exists)) {
$result[$key] = static::update($data, [], [], $suffix);
} else {
$result[$key] = static::create($data, $this->field, $this->replace, $suffix);
@@ -809,7 +831,7 @@ abstract class Model implements JsonSerializable, ArrayAccess, Arrayable, Jsonab
$db->transaction(function () use ($where, $db) {
// 删除当前模型数据
$db->where($where)->delete();
$db->where($where)->cache($this->cacheKey)->delete();
// 关联删除
if (!empty($this->relationWrite)) {

View File

@@ -770,10 +770,9 @@ abstract class BaseQuery
* @param mixed $key 缓存key
* @param integer|\DateTime $expire 缓存有效期
* @param string|array $tag 缓存标签
* @param bool $always 始终缓存
* @return $this
*/
public function cache($key = true, $expire = null, $tag = null, bool $always = false)
public function cache($key = true, $expire = null, $tag = null)
{
if (false === $key || !$this->getConnection()->getCache()) {
return $this;
@@ -784,8 +783,7 @@ abstract class BaseQuery
$key = true;
}
$this->options['cache'] = [$key, $expire, $tag];
$this->options['cache_always'] = $always;
$this->options['cache'] = [$key, $expire, $tag ?: $this->getTable()];
return $this;
}
@@ -800,7 +798,23 @@ abstract class BaseQuery
*/
public function cacheAlways($key = true, $expire = null, $tag = null)
{
return $this->cache($key, $expire, $tag, true);
$this->options['cache_always'] = true;
return $this->cache($key, $expire, $tag);
}
/**
* 强制更新缓存
*
* @param mixed $key 缓存key
* @param int|\DateTime $expire 缓存有效期
* @param string|array $tag 缓存标签
*
* @return $this
*/
public function cacheForce($key = true, $expire = null, $tag = null)
{
$this->options['force_cache'] = true;
return $this->cache($key, $expire, $tag);
}
/**
@@ -1026,6 +1040,23 @@ abstract class BaseQuery
return $this->connection->insertAll($this, $dataSet, $limit);
}
/**
* 批量插入记录
* @access public
* @param array $keys 键值
* @param array $values 数据
* @param integer $limit 每次写入数据限制
* @return integer
*/
public function insertAllByKeys(array $keys, array $values, int $limit = 0): int
{
if (empty($limit) && !empty($this->options['limit']) && is_numeric($this->options['limit'])) {
$limit = (int) $this->options['limit'];
}
return $this->connection->insertAllByKeys($this, $keys, $values, $limit);
}
/**
* 通过Select方式插入记录
* @access public

View File

@@ -1238,6 +1238,53 @@ abstract class Builder
);
}
/**
* 生成insertall SQL
* @access public
* @param Query $query 查询对象
* @param array $keys 字段名
* @param array $datas 数据
* @return string
*/
public function insertAllByKeys(Query $query, array $keys, array $datas): string
{
$options = $query->getOptions();
// 获取绑定信息
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
foreach ($keys as $field) {
$fields[] = $this->parseKey($query, $field);
}
foreach ($datas as $data) {
foreach ($data as $key => &$val) {
if (!$query->isAutoBind()) {
$val = PDO::PARAM_STR == $bind[$keys[$key]] ? '\'' . $val . '\'' : $val;
} else {
$val = $this->parseDataBind($query, $keys[$key], $val, $bind);
}
}
$values[] = 'SELECT ' . implode(',', $data);
}
return str_replace(
['%INSERT%', '%TABLE%', '%EXTRA%', '%FIELD%', '%DATA%', '%COMMENT%'],
[
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$this->parseTable($query, $options['table']),
$this->parseExtra($query, $options['extra']),
implode(' , ', $fields),
implode(' UNION ALL ', $values),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
}
/**
* 生成slect insert SQL
* @access public

View File

@@ -309,7 +309,7 @@ class Fetch
$this->query->setOption('soft_delete', null);
$this->query->setOption('data', [$field => $condition]);
// 生成删除SQL语句
$sql = $this->builder->delete($this->query);
$sql = $this->builder->update($this->query);
return $this->fetch($sql);
}
}

View File

@@ -622,15 +622,14 @@ abstract class PDOConnection extends Connection
* @access public
* @param BaseQuery $query 查询对象
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param Model|null $model 模型对象实例
* @param null $condition 查询条件
* @return \Generator
* @throws DbException
*/
public function getCursor(BaseQuery $query, string $sql, array $bind = [], $model = null, $condition = null)
public function getCursor(BaseQuery $query, string $sql, $model = null, $condition = null)
{
$this->queryPDOStatement($query, $sql, $bind);
$this->queryPDOStatement($query, $sql);
// 返回结果集
while ($result = $this->PDOStatement->fetch($this->fetchType)) {
@@ -653,7 +652,7 @@ abstract class PDOConnection extends Connection
*/
public function query(string $sql, array $bind = [], bool $master = false): array
{
return $this->pdoQuery($this->newQuery(), $sql, $bind, $master);
return $this->pdoQuery($this->newQuery()->bind($bind), $sql, $master);
}
/**
@@ -666,7 +665,7 @@ abstract class PDOConnection extends Connection
*/
public function execute(string $sql, array $bind = []): int
{
return $this->pdoExecute($this->newQuery(), $sql, $bind, true);
return $this->pdoExecute($this->newQuery()->bind($bind), $sql, true);
}
/**
@@ -674,25 +673,27 @@ abstract class PDOConnection extends Connection
* @access protected
* @param BaseQuery $query 查询对象
* @param mixed $sql sql指令
* @param array $bind 参数绑定
* @param bool $master 主库读取
* @return array
* @throws DbException
*/
protected function pdoQuery(BaseQuery $query, $sql, array $bind = [], bool $master = null): array
protected function pdoQuery(BaseQuery $query, $sql, bool $master = null): array
{
// 分析查询表达式
$query->parseOptions();
$bind = $query->getBind();
if ($query->getOptions('cache')) {
// 检查查询缓存
$cacheItem = $this->parseCache($query, $query->getOptions('cache'));
$key = $cacheItem->getKey();
if (!$query->getOptions('force_cache')) {
$key = $cacheItem->getKey();
$data = $this->cache->get($key);
$data = $this->cache->get($key);
if (null !== $data) {
return $data;
if (null !== $data) {
return $data;
}
}
}
@@ -730,11 +731,10 @@ abstract class PDOConnection extends Connection
*/
public function pdo(BaseQuery $query): PDOStatement
{
$bind = $query->getBind();
// 生成查询SQL
$sql = $this->builder->select($query);
return $this->queryPDOStatement($query, $sql, $bind);
return $this->queryPDOStatement($query, $sql);
}
/**
@@ -806,18 +806,17 @@ abstract class PDOConnection extends Connection
* @access protected
* @param BaseQuery $query 查询对象
* @param string $sql sql指令
* @param array $bind 参数绑定
* @param bool $origin 是否原生查询
* @return int
* @throws DbException
*/
protected function pdoExecute(BaseQuery $query, string $sql, array $bind = [], bool $origin = false): int
protected function pdoExecute(BaseQuery $query, string $sql, bool $origin = false): int
{
if ($origin) {
$query->parseOptions();
}
$this->queryPDOStatement($query->master(true), $sql, $bind);
$this->queryPDOStatement($query->master(true), $sql);
if (!$origin && !empty($this->config['deploy']) && !empty($this->config['read_master'])) {
$this->readMaster = true;
@@ -844,13 +843,13 @@ abstract class PDOConnection extends Connection
/**
* @param BaseQuery $query
* @param string $sql
* @param array $bind
* @return PDOStatement
* @throws DbException
*/
protected function queryPDOStatement(BaseQuery $query, string $sql, array $bind = []): PDOStatement
protected function queryPDOStatement(BaseQuery $query, string $sql): PDOStatement
{
$options = $query->getOptions();
$bind = $query->getBind();
$master = !empty($options['master']) ? true : false;
$procedure = !empty($options['procedure']) ? true : in_array(strtolower(substr(trim($sql), 0, 4)), ['call', 'exec']);
@@ -898,7 +897,7 @@ abstract class PDOConnection extends Connection
$condition = $options['where']['AND'] ?? null;
// 执行查询操作
return $this->getCursor($query, $sql, $query->getBind(), $query->getModel(), $condition);
return $this->getCursor($query, $sql, $query->getModel(), $condition);
}
/**
@@ -938,7 +937,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->insert($query);
// 执行操作
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind());
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql);
if ($result) {
$sequence = $options['sequence'] ?? null;
@@ -977,13 +976,12 @@ abstract class PDOConnection extends Connection
*/
public function insertAll(BaseQuery $query, array $dataSet = [], int $limit = 0): int
{
$query->parseOptions();
if (!is_array(reset($dataSet))) {
return 0;
}
$options = $query->parseOptions();
$replace = !empty($options['replace']);
if (0 === $limit && count($dataSet) >= 5000) {
$limit = 1000;
}
@@ -997,8 +995,8 @@ abstract class PDOConnection extends Connection
$count = 0;
foreach ($array as $item) {
$sql = $this->builder->insertAll($query, $item, $replace);
$count += $this->pdoExecute($query, $sql, $query->getBind());
$sql = $this->builder->insertAll($query, $item);
$count += $this->pdoExecute($query, $sql);
}
// 提交事务
@@ -1011,9 +1009,56 @@ abstract class PDOConnection extends Connection
return $count;
}
$sql = $this->builder->insertAll($query, $dataSet, $replace);
$sql = $this->builder->insertAll($query, $dataSet);
return $this->pdoExecute($query, $sql, $query->getBind());
return $this->pdoExecute($query, $sql);
}
/**
* 批量插入记录
* @access public
* @param BaseQuery $query 查询对象
* @param array $keys 键值
* @param array $values 数据
* @param integer $limit 每次写入数据限制
* @return integer
* @throws \Exception
* @throws \Throwable
*/
public function insertAllByKeys(BaseQuery $query, array $keys, array $values, int $limit = 0): int
{
$query->parseOptions();
if (0 === $limit && count($values) >= 5000) {
$limit = 1000;
}
if ($limit) {
// 分批写入 自动启动事务支持
$this->startTrans();
try {
$array = array_chunk($values, $limit, true);
$count = 0;
foreach ($array as $item) {
$sql = $this->builder->insertAllByKeys($query, $keys, $item);
$count += $this->pdoExecute($query, $sql);
}
// 提交事务
$this->commit();
} catch (\Exception | \Throwable $e) {
$this->rollback();
throw $e;
}
return $count;
}
$sql = $this->builder->insertAllByKeys($query, $keys, $values);
return $this->pdoExecute($query, $sql);
}
/**
@@ -1032,7 +1077,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->selectInsert($query, $fields, $table);
return $this->pdoExecute($query, $sql, $query->getBind());
return $this->pdoExecute($query, $sql);
}
/**
@@ -1050,7 +1095,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->update($query);
// 执行操作
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql, $query->getBind());
$result = '' == $sql ? 0 : $this->pdoExecute($query, $sql);
if ($result) {
$this->db->trigger('after_update', $query);
@@ -1075,7 +1120,7 @@ abstract class PDOConnection extends Connection
$sql = $this->builder->delete($query);
// 执行操作
$result = $this->pdoExecute($query, $sql, $query->getBind());
$result = $this->pdoExecute($query, $sql);
if ($result) {
$this->db->trigger('after_delete', $query);
@@ -1109,10 +1154,13 @@ abstract class PDOConnection extends Connection
if (!empty($options['cache'])) {
$cacheItem = $this->parseCache($query, $options['cache'], 'value');
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
if (!$query->getOptions('force_cache')) {
$key = $cacheItem->getKey();
if ($this->cache->has($key)) {
return $this->cache->get($key);
}
}
}
@@ -1208,10 +1256,12 @@ abstract class PDOConnection extends Connection
if (!empty($options['cache'])) {
// 判断查询缓存
$cacheItem = $this->parseCache($query, $options['cache'], 'column');
$name = $cacheItem->getKey();
if (!$query->getOptions('force_cache')) {
$name = $cacheItem->getKey();
if ($this->cache->has($name)) {
return $this->cache->get($name);
if ($this->cache->has($name)) {
return $this->cache->get($name);
}
}
}
@@ -1545,17 +1595,16 @@ abstract class PDOConnection extends Connection
* @access public
* @param BaseQuery $query 查询对象
* @param array $sqlArray SQL批处理指令
* @param array $bind 参数绑定
* @return bool
*/
public function batchQuery(BaseQuery $query, array $sqlArray = [], array $bind = []): bool
public function batchQuery(BaseQuery $query, array $sqlArray = []): bool
{
// 自动启动事务支持
$this->startTrans();
try {
foreach ($sqlArray as $sql) {
$this->pdoExecute($query, $sql, $bind);
$this->pdoExecute($query, $sql);
}
// 提交事务
$this->commit();

View File

@@ -111,8 +111,6 @@ class Mongo
$result[$item] = $val;
} elseif (isset($val[0]) && 'exp' == $val[0]) {
$result[$item] = $val[1];
} elseif (is_null($val)) {
$result[$item] = 'NULL';
} else {
$result[$item] = $this->parseValue($query, $val, $key);
}

View File

@@ -12,6 +12,7 @@ declare (strict_types = 1);
namespace think\db\builder;
use PDO;
use think\db\Builder;
use think\db\exception\DbException as Exception;
use think\db\Query;
@@ -27,7 +28,7 @@ class Mysql extends Builder
* @var array
*/
protected $parser = [
'parseCompare' => ['=', '<>', '>', '>=', '<', '<='],
'parseCompare' => ['=', '!=', '<>', '>', '>=', '<', '<='],
'parseLike' => ['LIKE', 'NOT LIKE'],
'parseBetween' => ['NOT BETWEEN', 'BETWEEN'],
'parseIn' => ['NOT IN', 'IN'],
@@ -146,10 +147,9 @@ class Mysql extends Builder
* @access public
* @param Query $query 查询对象
* @param array $dataSet 数据集
* @param bool $replace 是否replace
* @return string
*/
public function insertAll(Query $query, array $dataSet, bool $replace = false): string
public function insertAll(Query $query, array $dataSet): string
{
$options = $query->getOptions();
@@ -183,7 +183,55 @@ class Mysql extends Builder
return str_replace(
['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%FIELD%', '%DATA%', '%DUPLICATE%', '%COMMENT%'],
[
$replace ? 'REPLACE' : 'INSERT',
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$this->parseExtra($query, $options['extra']),
$this->parseTable($query, $options['table']),
$this->parsePartition($query, $options['partition']),
implode(' , ', $fields),
implode(' , ', $values),
$this->parseDuplicate($query, $options['duplicate']),
$this->parseComment($query, $options['comment']),
],
$this->insertAllSql
);
}
/**
* 生成insertall SQL
* @access public
* @param Query $query 查询对象
* @param array $keys 键值
* @param array $values 数据
* @return string
*/
public function insertAllByKeys(Query $query, array $keys, array $datas): string
{
$options = $query->getOptions();
// 获取绑定信息
$bind = $query->getFieldsBindType();
$fields = [];
$values = [];
foreach ($keys as $field) {
$fields[] = $this->parseKey($query, $field);
}
foreach ($datas as $data) {
foreach ($data as $key => &$val) {
if (!$query->isAutoBind()) {
$val = PDO::PARAM_STR == $bind[$keys[$key]] ? '\'' . $val . '\'' : $val;
} else {
$val = $this->parseDataBind($query, $keys[$key], $val, $bind);
}
}
$values[] = '( ' . implode(',', $data) . ' )';
}
return str_replace(
['%INSERT%', '%EXTRA%', '%TABLE%', '%PARTITION%', '%FIELD%', '%DATA%', '%DUPLICATE%', '%COMMENT%'],
[
!empty($options['replace']) ? 'REPLACE' : 'INSERT',
$this->parseExtra($query, $options['extra']),
$this->parseTable($query, $options['table']),
$this->parsePartition($query, $options['partition']),

View File

@@ -49,12 +49,21 @@ trait AggregateQuery
}
$options = $this->getOptions();
$subSql = $this->options($options)
if (isset($options['cache'])) {
$cache = $options['cache'];
unset($options['cache']);
}
$subSql = $this->options($options)
->field('count(' . $field . ') AS think_count')
->bind($this->bind)
->buildSql();
$query = $this->newQuery()->table([$subSql => '_group_count_']);
$query = $this->newQuery();
if (isset($cache)) {
$query->setOption('cache', $cache);
}
$query->table([$subSql => '_group_count_']);
$count = $query->aggregate('COUNT', '*');
} else {

View File

@@ -258,7 +258,7 @@ class Mongo extends Connection
$this->queryStartTime = microtime(true);
if ($session = $this->getSession()) {
$this->cursor = $this->mongo->executeQuery($namespace, $query, [
$this->cursor = $this->mongo->executeQuery($namespace, $mongoQuery, [
'readPreference' => is_null($readPreference) ? new ReadPreference(ReadPreference::RP_PRIMARY) : $readPreference,
'session' => $session,
]);

View File

@@ -264,7 +264,7 @@ class HasMany extends Relation
// 保存关联表数据
$data[$this->foreignKey] = $this->parent->{$this->localKey};
return new $this->model($data);
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
}
/**

View File

@@ -151,14 +151,10 @@ class HasOneThrough extends HasManyThrough
->select();
// 组装模型数据
$data = [];
$keys = array_flip($keys);
foreach ($list as $set) {
$data[$keys[$set->{$this->throughKey}]] = $set;
}
return $data;
return array_map(function ($key) use ($list) {
$set = $list->where($this->throughKey, '=', $key)->first();
return $set ? clone $set : null;
}, $keys);
}
}

View File

@@ -315,7 +315,7 @@ class MorphMany extends Relation
$data[$this->morphKey] = $this->parent->$pk;
$data[$this->morphType] = $this->type;
return new $this->model($data);
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
}
/**

View File

@@ -284,7 +284,7 @@ class MorphOne extends Relation
$data[$this->morphKey] = $this->parent->$pk;
$data[$this->morphType] = $this->type;
return new $this->model($data);
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
}
/**

View File

@@ -224,7 +224,7 @@ abstract class OneToOne extends Relation
// 保存关联表数据
$data[$this->foreignKey] = $this->parent->{$this->localKey};
return new $this->model($data);
return (new $this->model($data))->setSuffix($this->getModel()->getSuffix());
}
/**