From 70f775a61648362406b81168eaba8ebf5a777d6d Mon Sep 17 00:00:00 2001 From: ThinkPHP Date: Fri, 24 Feb 2023 12:11:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0setInc=E5=92=8CsetDec?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=94=A8=E4=BA=8E=E6=95=B0=E5=80=BC=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E7=9A=84=E8=87=AA=E5=A2=9E=E5=92=8C=E8=87=AA=E5=87=8F?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=20=E5=B9=B6=E6=94=AF=E6=8C=81=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E5=86=99=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Model.php | 4 +- src/db/BaseQuery.php | 48 ++++++++- src/db/Query.php | 135 ++++++++++++++++++++++++++ src/db/concern/ModelRelationQuery.php | 8 ++ src/db/concern/ResultOperation.php | 8 ++ src/db/concern/WhereQuery.php | 5 + src/model/concern/Attribute.php | 7 ++ 7 files changed, 213 insertions(+), 2 deletions(-) diff --git a/src/Model.php b/src/Model.php index 8e9a2adf..6c9a8385 100644 --- a/src/Model.php +++ b/src/Model.php @@ -388,7 +388,9 @@ public function db($scope = []): Query $query->model($this) ->json($this->json, $this->jsonAssoc) - ->setFieldType(array_merge($this->schema, $this->jsonType)); + ->setFieldType(array_merge($this->schema, $this->jsonType)) + ->setKey($this->getKey()) + ->lazyFields($this->lazyFields); // 软删除 if (property_exists($this, 'withTrashed') && !$this->withTrashed) { diff --git a/src/db/BaseQuery.php b/src/db/BaseQuery.php index d20d9d8e..756d4578 100644 --- a/src/db/BaseQuery.php +++ b/src/db/BaseQuery.php @@ -14,6 +14,7 @@ namespace think\db; use Closure; +use Psr\SimpleCache\CacheInterface; use think\Collection; use think\db\exception\DataNotFoundException; use think\db\exception\DbException as Exception; @@ -203,6 +204,41 @@ public function getName(): string return $this->name ?: $this->model->getName(); } + /** + * 设置主键值. + * + * @param mixed $key 主键值 + * + * @return $this + */ + public function setKey($key) + { + $this->options['key'] = $key; + + return $this; + } + + /** + * 获取主键值. + * @param array $data 数据 + * + * @return mixed + */ + public function getKey(array $data = []) + { + if (!empty($data)) { + $pk = $this->getPk(); + if (is_string($pk) && isset($data[$pk])) { + $id = $data[$pk]; + } else { + $id = null; + } + return $id; + } + + return $this->getOptions('key'); + } + /** * 获取数据库的配置参数. * @@ -835,6 +871,16 @@ public function more(int $limit, int|string $lastId = null, string $key = null, ]; } + /** + * 获取当前的缓存对象 + * + * @return CacheInterface|null + */ + public function getCache() + { + return $this->getConnection()->getCache(); + } + /** * 查询缓存 数据为空不缓存. * @@ -847,7 +893,7 @@ public function more(int $limit, int|string $lastId = null, string $key = null, */ public function cache($key = true, $expire = null, $tag = null, bool $always = false) { - if (false === $key || !$this->getConnection()->getCache()) { + if (false === $key || !$this->getCache()) { return $this; } diff --git a/src/db/Query.php b/src/db/Query.php index 4593e3f9..252acace 100644 --- a/src/db/Query.php +++ b/src/db/Query.php @@ -14,6 +14,7 @@ namespace think\db; use PDOStatement; +use think\db\exception\DbException as Exception; /** * PDO数据查询类. @@ -387,6 +388,140 @@ public function dec(string $field, float $step = 1) return $this; } + /** + * 设置延迟写入字段 用于实时获取缓存数据 + * + * @param array $fields 延迟写入字段 + * + * @return $this + */ + public function lazyFields(array $fields) + { + $this->options['lazy_fields'] = $fields; + + return $this; + } + + /** + * 字段值增长(支持延迟写入) + * + * @param string $field 字段名 + * @param int $step 步进值 + * @param int $lazyTime 延迟时间(秒) + * + * @return int|false + */ + public function setInc(string $field, int $step = 1, $lazyTime = 0) + { + if (empty($this->options['where']) && $this->model) { + $this->where($this->model->getWhere()); + } + + if (empty($this->options['where'])) { + // 如果没有任何更新条件则不执行 + throw new Exception('miss update condition'); + } + + if ($lazyTime > 0) { + $guid = $this->getLazyFieldCacheKey($field); + $step = $this->lazyWrite('inc', $guid, $step, $lazyTime); + if (false === $step) { + return true; + } + } + + return $this->inc($field, $step)->update(); + } + + /** + * 字段值减少(支持延迟写入) + * + * @param string $field 字段名 + * @param int $step 步进值 + * @param int $lazyTime 延迟时间(秒) + * + * @return int|false + */ + public function setDec(string $field, int $step = 1, int $lazyTime = 0) + { + if (empty($this->options['where']) && $this->model) { + $this->where($this->model->getWhere()); + } + + if (empty($this->options['where'])) { + // 如果没有任何更新条件则不执行 + throw new Exception('miss update condition'); + } + + if ($lazyTime > 0) { + $guid = $this->getLazyFieldCacheKey($field); + $step = $this->lazyWrite('dec', $guid, $step, $lazyTime); + if (false === $step) { + return true; + } + return $this->inc($field, $step)->update(); + } + + return $this->dec($field, $step)->update(); + } + + /** + * 延时更新检查 返回false表示需要延时 + * 否则返回实际写入的数值 + * @access protected + * @param string $type 自增或者自减 + * @param string $guid 写入标识 + * @param int $step 写入步进值 + * @param int $lazyTime 延时时间(s) + * @return false|integer + */ + protected function lazyWrite(string $type, string $guid, int $step, int $lazyTime) + { + $cache = $this->getCache(); + if (!$cache->has($guid . '_time')) { + // 计时开始 + $cache->set($guid . '_time', time()); + $cache->$type($guid, $step); + } elseif (time() > $cache->get($guid . '_time') + $lazyTime) { + // 删除缓存 + $value = $cache->$type($guid, $step); + $cache->delete($guid); + $cache->delete($guid . '_time'); + return 0 === $value ? false : $value; + } else { + // 更新缓存 + $cache->$type($guid, $step); + } + + return false; + } + + /** + * 获取延迟写入字段值. + * + * @param string $field 字段名称 + * @param mixed $id 主键值 + * + * @return int + */ + protected function getLazyFieldValue(string $field, $id = null): int + { + return (int) $this->getCache()->get($this->getLazyFieldCacheKey($field, $id)); + } + + /** + * 获取延迟写入字段的缓存Key + * + * @param string $field 字段名 + * @param mixed $id 主键值 + * + * @return string + */ + protected function getLazyFieldCacheKey(string $field, $id = null): string + { + return 'lazy_' . $this->getTable() . '_' . $field . '_' . ($id ?: $this->getKey()); + } + /** * 获取当前的查询标识. * diff --git a/src/db/concern/ModelRelationQuery.php b/src/db/concern/ModelRelationQuery.php index b2054afc..4f31fd13 100644 --- a/src/db/concern/ModelRelationQuery.php +++ b/src/db/concern/ModelRelationQuery.php @@ -579,6 +579,14 @@ protected function resultToModel(array &$result): void $this->jsonModelResult($result); } + // 实时读取延迟数据 + if (!empty($this->options['lazy_fields'])) { + $id = $this->getKey($result); + foreach ($this->options['lazy_fields'] as $field) { + $result[$field] += $this->getLazyFieldValue($field, $id); + } + } + $result = $this->model->newInstance( $result, !empty($this->options['is_resultSet']) ? null : $this->getModelUpdateCondition($this->options), diff --git a/src/db/concern/ResultOperation.php b/src/db/concern/ResultOperation.php index a7c7f3bf..d5db9496 100644 --- a/src/db/concern/ResultOperation.php +++ b/src/db/concern/ResultOperation.php @@ -88,6 +88,14 @@ protected function result(array &$result): void $this->jsonResult($result); } + // 实时读取延迟数据 + if (!empty($this->options['lazy_fields'])) { + $id = $this->getKey($result); + foreach ($this->options['lazy_fields'] as $field) { + $result[$field] += $this->getLazyFieldValue($field, $id); + } + } + // 查询数据处理 foreach ($this->options['filter'] as $filter) { $result = call_user_func_array($filter, [$result, $this->options]); diff --git a/src/db/concern/WhereQuery.php b/src/db/concern/WhereQuery.php index c5affa9d..05866764 100644 --- a/src/db/concern/WhereQuery.php +++ b/src/db/concern/WhereQuery.php @@ -40,6 +40,11 @@ public function where($field, $op = null, $condition = null) return $this; } + $pk = $this->getPk(); + if ((is_null($condition) || '=' == $op) && is_string($pk) && $pk == $field ) { + $this->options['key'] = is_null($condition) ? $op : $condition; + } + $param = func_get_args(); array_shift($param); diff --git a/src/model/concern/Attribute.php b/src/model/concern/Attribute.php index 7b408aea..de0bcc8f 100644 --- a/src/model/concern/Attribute.php +++ b/src/model/concern/Attribute.php @@ -123,6 +123,13 @@ trait Attribute */ private $withAttr = []; + /** + * 数据表延迟写入的字段 + * + * @var array + */ + protected $lazyFields = []; + /** * 获取模型对象的主键. *