hyperf 二十四 模型缓存

教程:Hyperf

一 安装及配置

1.1 安装

目前仅支持redis。

composer require hyperf/model-cache

 1.2 配置

配置位置:config/autoload/databases.php

配置类型默认值备注
handlerstringHyperf\ModelCache\Handler\RedisHandler::class
cache_keystringmc:%s:m:%s:%s:%smc:缓存前缀:m:表名:主键 KEY:主键值
prefixstringdb connection name缓存前缀
poolstringdefault缓存池
ttlint3600超时时间
empty_model_ttlint60查询不到数据时的超时时间
load_scriptbooltrueRedis 引擎下 是否使用 evalSha 代替 eval
use_default_valueboolfalse是否使用数据库默认值
return ['default' => [……'cache' => ['handler' => \Hyperf\ModelCache\Handler\RedisHandler::class,'cache_key' => 'mc:%s:m:%s:%s:%s','prefix' => 'default','ttl' => 3600 * 24,'empty_model_ttl' => 3600,'load_script' => true,'use_default_value' => false,]],
];

 该配置参数在Hyperf\ModelCache\Manager::__construct()中使用,该方法在调用Hyperf\ModelCache\Cacheable的成员方法时被调用。即每次查询和修改缓存执行一次redis连接。

二 使用

2.1 查询

#App1\Model\Article 
use Hyperf\ModelCache\Cacheable;
use Hyperf\ModelCache\CacheableInterface;
class Article extends Model implements CacheableInterface {use Cacheable;……
}#App\Controller\TestController
public function testmodelcache() {$model = Article::findFromCache(1)->toArray();var_dump($model);$models = Article::findManyFromCache([1, 2])->toArray();var_dump($models);}
}

 测试结果

array(6) {["id"]=>int(1)["user_id"]=>string(1) "1"["title"]=>string(5) "test1"["created_at"]=>string(19) "2024-01-13 10:05:51"["updated_at"]=>string(19) "2024-01-13 10:05:53"["deleted_at"]=>string(0) ""
}array(2) {[0]=>array(6) {["id"]=>int(1)["user_id"]=>string(1) "1"["title"]=>string(5) "test1"["created_at"]=>string(19) "2024-01-13 10:05:51"["updated_at"]=>string(19) "2024-01-13 10:05:53"["deleted_at"]=>string(0) ""}[1]=>array(6) {["id"]=>int(2)["user_id"]=>string(1) "1"["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-01-13 10:06:06"["deleted_at"]=>string(0) ""}
}

 redis结果

keys *
1) "mc:default:m:articles:id:2"
2) "mc:default:m:articles:id:1"
3) "test"
4) "n0fsWPgnTRdnlB2VHFdhyPLAZlEZ4HgC1RdurOpV"type  mc:default:m:articles:id:1
hashhgetall mc:default:m:articles:id:11) "id"2) "1"3) "user_id"4) "1"5) "title"6) "test1"7) "created_at"8) "2024-01-13 10:05:51"9) "updated_at"
10) "2024-01-13 10:05:53"
11) "deleted_at"
12) ""
13) "HF-DATA"
14) "DEFAULT"

 每次查询先获取链接,再判断缓存中是否有对应key值,没有则向缓存设置。

2.2 修改或删除

模型中使用的Cacheable,重写了修改和删除,以便处理缓存。

测试 缓存写入

 $model = Article::findFromCache(3)->toArray();var_dump($model);

 测试结果

array(6) {["id"]=>int(3)["user_id"]=>int(2)["title"]=>string(5) "test3"["created_at"]=>string(19) "2024-01-30 13:38:46"["updated_at"]=>NULL["deleted_at"]=>NULL
}127.0.0.1:6379> keys *
1) "mc:default:m:articles:id:3"
2) "mc:default:m:articles:id:2"
3) "mc:default:m:articles:id:1"
4) "test"
127.0.0.1:6379> hgetall "mc:default:m:articles:id:3"1) "id"2) "3"3) "user_id"4) "2"5) "title"6) "test3"7) "created_at"8) "2024-01-30 13:38:46"9) "updated_at"
10) ""
11) "deleted_at"
12) ""
13) "HF-DATA"
14) "DEFAULT"

 测试 缓存删除

$res = Article::query(true)->where('id', '=', 3)->delete();
var_dump($res);

测试结果

int(1)127.0.0.1:6379> keys *
1) "mc:default:m:articles:id:2"
2) "mc:default:m:articles:id:1"
3) "test"

 Cacheable复写的query()通过传入参数设置设否使用缓存。Cacheable复写的newModelBuilder()实现缓存控制。

2.3 使用默认值

根据文档,设置默认值适用于数据库新加字段和缓存数据的适配。

#新加数据库字段
ALTER TABLE `test`.`articles` 
ADD COLUMN `pv_num` int(4) NULL DEFAULT 0 COMMENT '浏览量' AFTER `deleted_at`;
#添加监听
#config\autoload\listeners.php
return [……"Hyperf\DbConnection\Listener\InitTableCollectorListener",
];
#修改设置
return ['default' => ['cache' => [……'use_default_value' => true,],]
]
$model = Article::findFromCache(1)->toArray();
var_dump($model);

 测试结果

array(7) {["id"]=>int(1)["user_id"]=>string(1) "1"["title"]=>string(5) "test1"["created_at"]=>string(19) "2024-01-13 10:05:51"["updated_at"]=>string(19) "2024-01-13 10:05:53"["deleted_at"]=>string(0) ""["pv_num"]=>string(1) "0"
}
127.0.0.1:6379> hgetall mc:default:m:articles:id:11) "id"2) "1"3) "user_id"4) "1"5) "title"6) "test1"7) "created_at"8) "2024-01-13 10:05:51"9) "updated_at"
10) "2024-01-13 10:05:53"
11) "deleted_at"
12) ""
13) "HF-DATA"
14) "DEFAULT"

再次获取数据,若缓存之中有数据则直接获取缓存数据。可以看见缓存中是没有浏览量字段,但是查出的结果中有对应字段。

为了证明不是从数据直接取值,第一可以查询数据库日志。

日志情况如下。可以看到仅查了一次之后删除,之后查的是数据库字段。

[2024-01-30 05:43:52] sql.INFO: [1.61] select `id` from `articles` where `id` = '3' and `articles`.`deleted_at` is null [] []
[2024-01-30 05:43:52] sql.INFO: [82.67] update `articles` set `deleted_at` = '2024-01-30 05:43:52', `articles`.`updated_at` = '2024-01-30 05:43:52' where `id` = '3' and `articles`.`deleted_at` is null [] []
[2024-01-30 06:45:17] sql.INFO: [195.56] select `table_schema`, `table_name`, `column_name`, `ordinal_position`, `column_default`, `is_nullable`, `data_type`, `column_comment` from information_schema.columns where `table_schema` = 'test' order by ORDINAL_POSITION [] []
[2024-01-30 06:45:17] sql.INFO: [186.61] select `table_schema`, `table_name`, `column_name`, `ordinal_position`, `column_default`, `is_nullable`, `data_type`, `column_comment` from information_schema.columns where `table_schema` = 'test' order by ORDINAL_POSITION [] []
[2024-01-30 06:45:17] sql.INFO: [260.73] select `table_schema`, `table_name`, `column_name`, `ordinal_position`, `column_default`, `is_nullable`, `data_type`, `column_comment` from information_schema.columns where `table_schema` = 'test' order by ORDINAL_POSITION [] []

 还可以先改数据再看运行结果。比如我直接改数据库对应id的pv_num值为1,但是查出的还是为0,但是调用update等修改方法,应该就能刷新缓存。

大概流程是查出表结构,和查出的数据集做对比,然后设置。

2.4 控制缓存时间

Hyperf\ModelCache\Manager设置缓存时使用Manager::getCacheTTL(),设置缓存值的过期时间。

Hyperf\ModelCache\Manager::getCacheTTL()获取缓存时间,其中调用Hyperf\ModelCache\Cacheable::getCacheTTL(),根据其返回值判断。若Cacheable::getCacheTTL()返回null则使用配置文件的值,否之使用Cacheable::getCacheTTL()的值。

根据文档是修改Cacheable::getCacheTTL()返回值,或者直接改配置文件的ttl的值。Cacheable::getCacheTTL()系统文件中未修改返回null,即默认使用配置文件。

2.5 预加载

用于解决多次查询问题,组后调用Hyperf\ModelCache\Manager::findManyFromCache()方法,使用whereIn查询。

官网提供两种方法,一个是使用监听,一个手动调用EagerLoader::load()。其实监听也是调用EagerLoader::load()。

model::loadCache()就是调用EagerLoader::load()。

EagerLoader::load()会执行查询对应关系数据的sql。

测试内容结合hyperf 二十三 分页-CSDN博客 中Article::author()设置。

$obj = Article::findManyFromCache([1, 2, 3]);
$obj->loadCache(['author']);
foreach ($obj as $item) {var_dump($item->toArray());
}

测试结果

array(8) {["id"]=>int(1)["user_id"]=>int(1)["title"]=>string(5) "test1"["created_at"]=>string(19) "2024-01-13 10:05:51"["updated_at"]=>string(19) "2024-01-13 10:05:53"["deleted_at"]=>NULL["pv_num"]=>int(1)["author"]=>array(4) {["id"]=>int(1)["name"]=>string(3) "123"["age"]=>int(22)["deleted_at"]=>NULL}
}
array(8) {["id"]=>int(2)["user_id"]=>int(1)["title"]=>string(5) "test2"["created_at"]=>string(19) "2024-01-13 10:06:04"["updated_at"]=>string(19) "2024-01-13 10:06:06"["deleted_at"]=>NULL["pv_num"]=>int(0)["author"]=>array(4) {["id"]=>int(1)["name"]=>string(3) "123"["age"]=>int(22)["deleted_at"]=>NULL}
}

 日志内容

[2024-01-30 09:49:46] sql.INFO: [40.81] select * from `articles` where `id` in ('1', '2', '3') and `articles`.`deleted_at` is null [] []
[2024-01-30 09:49:46] sql.INFO: [15.48] select * from `userinfo` where `userinfo`.`id` in (1) and `userinfo`.`deleted_at` is null [] []

三 缓存适配器

继承Hyperf\ModelCache\Handler\HandlerInterface,参考Hyperf\ModelCache\Handler\RedisHandler和Hyperf\ModelCache\Handler\RedisStringHandler。

自己写着练手的项目打算用PostgreSql,还在研究。学习差不多之后,这个内容打算之后再开一篇文章。

四 源码

4.1 配置使用

#Hyperf\ModelCache\Manager
public function __construct(ContainerInterface $container) {$this->container = $container;$this->logger = $container->get(StdoutLoggerInterface::class);$this->collector = $container->get(TableCollector::class);$config = $container->get(ConfigInterface::class);if (!$config->has('databases')) {throw new InvalidArgumentException('config databases is not exist!');}foreach ($config->get('databases') as $key => $item) {$handlerClass = $item['cache']['handler'] ?? RedisHandler::class;$config = new Config($item['cache'] ?? [], $key);/** @var HandlerInterface $handler */$handler = make($handlerClass, ['config' => $config]);$this->handlers[$key] = $handler;}}#Hyperf\ModelCache\Cacheable
public static function findFromCache($id): ?Model{$container = ApplicationContext::getContainer();$manager = $container->get(Manager::class);return $manager->findFromCache($id, static::class);}

4.2 缓存数据设计及更新

#Hyperf\ModelCache\Cacheable 
use Hyperf\ModelCache\Builder as ModelCacheBuilder;
public static function query(bool $cache = false): Builder{return (new static())->newQuery($cache);}
public function newModelBuilder($query): Builder{if ($this->useCacheBuilder) {return new ModelCacheBuilder($query);}return parent::newModelBuilder($query);}#Hyperf\Database\Mode\Model
public function newQuery() {return $this->registerGlobalScopes($this->newQueryWithoutScopes());}
public function newQueryWithoutScopes() {return $this->newModelQuery()->with($this->with)->withCount($this->withCount);}
public function newModelQuery() {return $this->newModelBuilder($this->newBaseQueryBuilder())->setModel($this);}#Hyperf\ModelCache\Builder
namespace Hyperf\ModelCache;use Hyperf\Database\Model\Builder as ModelBuilder;
use Hyperf\Utils\ApplicationContext;class Builder extends ModelBuilder
{public function delete(){return $this->deleteCache(function () {return parent::delete();});}public function update(array $values){return $this->deleteCache(function () use ($values) {return parent::update($values);});}protected function deleteCache(\Closure $closure){$queryBuilder = clone $this;$primaryKey = $this->model->getKeyName();$ids = [];$models = $queryBuilder->get([$primaryKey]);foreach ($models as $model) {$ids[] = $model->{$primaryKey};}if (empty($ids)) {return 0;}$result = $closure();$manger = ApplicationContext::getContainer()->get(Manager::class);$manger->destroy($ids, get_class($this->model));return $result;}
}#Hyperf\Database\Model\Builder
public function __construct(QueryBuilder $query) {$this->query = $query;}

4.3 设置默认值

#Hyperf\DbConnection\Listener\InitTableCollectorListener
use Hyperf\DbConnection\Collector\TableCollector;
class InitTableCollectorListener implements ListenerInterface {/*** @var ContainerInterface*/protected $container;/*** @var ConfigInterface*/protected $config;/*** @var StdoutLoggerInterface*/protected $logger;/*** @var TableCollector*/protected $collector;public function __construct(ContainerInterface $container) {$this->container = $container;$this->config = $container->get(ConfigInterface::class);$this->logger = $container->get(StdoutLoggerInterface::class);$this->collector = $container->get(TableCollector::class);}public function listen(): array {return [BeforeHandle::class,AfterWorkerStart::class,BeforeProcessHandle::class,];}public function process(object $event) {try {$databases = $this->config->get('databases', []);$pools = array_keys($databases);foreach ($pools as $name) {$this->initTableCollector($name);}} catch (\Throwable $throwable) {$this->logger->error((string) $throwable);}}public function initTableCollector(string $pool) {if ($this->collector->has($pool)) {return;}/** @var ConnectionResolverInterface $connectionResolver */$connectionResolver = $this->container->get(ConnectionResolverInterface::class);/** @var MySqlConnection $connection */$connection = $connectionResolver->connection($pool);/** @var \Hyperf\Database\Schema\Builder $schemaBuilder */$schemaBuilder = $connection->getSchemaBuilder();$columns = $schemaBuilder->getColumns();foreach ($columns as $column) {$this->collector->add($pool, $column);}}
}
#Hyperf\DbConnection\Collector\TableCollector
namespace Hyperf\DbConnection\Collector;use Hyperf\Database\Schema\Column;class TableCollector
{/*** @var array*/protected $data = [];/*** @param Column[] $columns*/public function set(string $pool, string $table, array $columns){$this->validateColumns($columns);$this->data[$pool][$table] = $columns;}public function add(string $pool, Column $column){$this->data[$pool][$column->getTable()][$column->getName()] = $column;}public function get(string $pool, ?string $table = null): array{if ($table === null) {return $this->data[$pool] ?? [];}return $this->data[$pool][$table] ?? [];}public function has(string $pool, ?string $table = null): bool{return ! empty($this->get($pool, $table));}public function getDefaultValue(string $connectName, string $table): array{$columns = $this->get($connectName, $table);$list = [];foreach ($columns as $column) {$list[$column->getName()] = $column->getDefault();}return $list;}/*** @throws \InvalidArgumentException When $columns is not equal to Column[]*/protected function validateColumns(array $columns): void{foreach ($columns as $column) {if (! $column instanceof Column) {throw new \InvalidArgumentException('Invalid columns.');}}}
}

4.4 设置模型关系

#Hyperf\ModelCache\Listener\EagerLoadListener
use Hyperf\ModelCache\EagerLoad\EagerLoader;
class EagerLoadListener implements ListenerInterface
{protected $container;public function __construct(ContainerInterface $container){$this->container = $container;}public function listen(): array{return [BootApplication::class,];}public function process(object $event){$eagerLoader = $this->container->get(EagerLoader::class);Collection::macro('loadCache', function ($parameters) use ($eagerLoader) {$eagerLoader->load($this, $parameters);});}
}
#Hyperf\ModelCache\EagerLoad\EagerLoader
use Hyperf\Database\Query\Builder as QueryBuilder;
class EagerLoader
{public function load(Collection $collection, array $relations){if ($collection->isNotEmpty()) {/** @var Model $first */$first = $collection->first();$query = $first->registerGlobalScopes($this->newBuilder($first))->with($relations);$collection->fill($query->eagerLoadRelations($collection->all()));}}protected function newBuilder(Model $model): Builder{$builder = new EagerLoaderBuilder($this->newBaseQueryBuilder($model));return $builder->setModel($model);}/*** Get a new query builder instance for the connection.** @return \Hyperf\Database\Query\Builder*/protected function newBaseQueryBuilder(Model $model){/** @var Connection $connection */$connection = $model->getConnection();return new QueryBuilder($connection, $connection->getQueryGrammar(), $connection->getPostProcessor());}
}

4.5 适配

#Hyperf\ModelCache\Handler\HandlerInterface
interface HandlerInterface extends CacheInterface
{public function getConfig(): Config;public function incr($key, $column, $amount): bool;
}
#Psr\SimpleCache\CacheInterface
namespace Psr\SimpleCache;interface CacheInterface
{/***从缓存中获取一个值。* @param string $key该项在缓存中的唯一键。* @param mixed $default键不存在时返回的默认值。* @return mix缓存项的值,如果缓存失败,则为$default。** @throws \Psr\SimpleCache\InvalidArgumentException*   如果$key字符串不是合法值,必须抛出。*/public function get($key, $default = null);/*** 设置缓存字段和TTL过期时间** @param string                 $key   存储键名* @param mixed                  $value 存储键值,必须可序列化* @param null|int|\DateInterval $ttl   过期时间,为空则使用配置文件(驱动)或redis过期时间** @return bool 成功返回true,失败返回false** @throws \Psr\SimpleCache\InvalidArgumentException*   如果$key字符串不是合法值,必须抛出。*/public function set($key, $value, $ttl = null);/*** 根据唯一键删除缓存** @param string $key 用于删除的唯一键名** @return bool 成功返回true,失败返回false** @throws \Psr\SimpleCache\InvalidArgumentException*   如果$key字符串不是合法值,必须抛出。*/public function delete($key);/*** 擦除清除整个缓存的键。** @return bool 成功返回true,失败返回false*/public function clear();/*** 根据其唯一键获取多个缓存项。** @param iterable $keys    在一次操作中可以获得的键的列表。* @param mixed    $default 对于不存在的键返回的默认值。** @return 返回键值对形式的数组,过期数据使用默认值** @throws \Psr\SimpleCache\InvalidArgumentException*   任何$key字符串不是合法值,必须抛出。*/public function getMultiple($keys, $default = null);/*** 设置键值对数组的缓存,并设置过期时间TTL.** @param iterable               $values 键值对数组* @param null|int|\DateInterval $ttl    过期时间*                                       ** @return bool 成功返回true,失败返回false** @throws \Psr\SimpleCache\InvalidArgumentException*   任何$key字符串不是合法值,必须抛出。*/public function setMultiple($values, $ttl = null);/*** 在单个操作中删除多个缓存项。** @param iterable $keys 要删除的基于字符串的键的列表。** @return bool 成功返回true,失败返回false** @throws \Psr\SimpleCache\InvalidArgumentException*   任何$key字符串不是合法值,必须抛出。*/public function deleteMultiple($keys);/*** 确定项是否存在于缓存中。* 注意:建议has()仅用于缓存升温类型* 而不是在您的实时应用程序操作中使用get/set,就像这个方法一样* 受竞争条件的约束,其中has()将返回true,并立即返回。* 另一个脚本可以删除它,使你的应用程序的状态过时。** @param string $key 键名** @return bool 成功返回true,失败返回false** @throws \Psr\SimpleCache\InvalidArgumentException*   如果$key字符串不是合法值,必须抛出。*/public function has($key);
}

其中has()的注意事项没有看懂。官网说参考Hyperf\ModelCache\Handler\RedisStringHandler。但是框架中并没有使用,应该是可以替换配置的RedisHandler。

'handler' => \Hyperf\ModelCache\Handler\RedisHandler::class,

 但是能查到has()使用代码示例。

#Hyperf\ModelCache\Manager
public function increment($id, $column, $amount, string $class): bool {/** @var Model $instance */$instance = new $class();$name = $instance->getConnectionName();if ($handler = $this->handlers[$name] ?? null) {$key = $this->getCacheKey($id, $instance, $handler->getConfig());if ($handler->has($key)) {return $handler->incr($key, $column, $amount);}return false;}$this->logger->alert('Cache handler not exist, increment failed.');return false;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/659716.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python时间格式数据处理。

由于编码和格式问题,有时候从read_csv或者read_excel读取到的时间类型是不确定的。 1.字符串转datetime.datetime时间格式 如果是字符串string类型,则可以使用: df[PDATE] pd.to_datetime(df[PDATE]).dt.date 转换为date格式&#xff0c…

开发安全之:Header Manipulation

Overview 方法 echo_json() 包含未验证的数据, 这会招致各种形式的攻击,包括:cache-poisoning、cross-site scripting、cross-user defacement、page hijacking、cookie manipulation 或 open redirect。 Details 以下情况中会出现 Header …

Websocket基本用法

1.Websocket介绍 WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 应用场景: 视频弹幕网页聊天体育实况更新股票基金…

基于OpenCV的高压电力检测项目案例

一、项目背景与目标 随着高压电力设施的日益增多,传统的巡检方式已无法满足现代电力系统的需求。为此,我们决定利用计算机视觉技术,特别是OpenCV库,开发一个高压电力检测系统。目标是实现自动化、高精度的电力设备检测&#xff0c…

P1228 地毯填补问题(葬送的芙蓉王【bushi】)

地毯填补问题 题目描述 相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外的所有地…

【零基础学习CAPL】——CAN报文的发送(配合Panel面板单次发送)

🙋‍♂️【零基础学习CAPL】系列💁‍♂️点击跳转 文章目录 1.概述2.面板创建2.1.新建一个Panel2.2. 在Panel中调出控件窗口2.3.控件添加与配置3.系统变量创建4.系统变量与Panel绑定5.CAPL脚本实现6.效果1.概述 使用场景,按下面板按钮同时发送报文。 本章主要介绍 CAPL脚…

Redis -- String 字符串, 计数命令,字符串操作

"学如逆水行舟,不进则退。" 目录 Redis的String字符串 常见命令 set get mget mset setnx setex psetex 计数命令 incr incrby decr decrby incrbyfloat 字符串操作 append getrange setrange strlen 小结 string内部编码 Redis…

文生图提示词:自然景观

场景描述 --自然景观 Natural Landscapes 涵盖了多种自然景观,可以用于精确地表达 AI 生成图像中所需的自然环境。 Mountain 山脉 River 河流 Forest 森林 Beach 海滩 Ocean 海洋 Lake 湖泊 Waterfall 瀑布 Desert 沙漠 Valley 山谷 Meadow 草地 Glacier 冰川 Cliff…

分布式系统唯一ID方案

分布式系统唯一ID方案 一、引言 在当今数字化时代,分布式系统的发展势不可挡,从云服务到微服务架构,都凸显了分布式系统在构建大规模、高效的应用中的重要性。而在这个庞大而复杂的系统中,唯一ID的生成和管理变得至关重要。唯一…

springboot137欢迪迈手机商城设计与开发

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计,课程设计参考与学习用途。仅供学习参考, 不得用于商业或者非法用途,否则,一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

通过与chatGPT交流实现零样本事件抽取

1、写作动机: 近来的大规模语言模型(例如Chat GPT)在零样本设置下取得了很好的表现,这启发作者探索基于提示的方法来解决零样本IE任务。 2、主要贡献: 提出了基于chatgpt的多阶段的信息抽取方法:在第一阶…

6、应急响应-日志自动提取自动分析ELKLogkitLogonTracerAnolog等

用途:个人学习笔记,欢迎指正 目录 背景: 一、日志自动提取-七牛Logki&观星应急工具 1、七牛Logkit: (支持Windows&Linux&Mac等) 2、观星应急工具(只支持Windows) 二、日志自动分析-Web-360星图&Goaccess&ALB&Anolog 1、W…

uniapp 使用canvas 画海报,有手粘贴即可用(拆成组件了,看后面)

1.直接使用 html部分 <view click"doposter">下载海报</view> <canvas canvas-id"myCanvas" type2d style"width: 370px; height: 550px;opcity:0;position: fixed;z-index:-1;" id"myCanvas" />js 部分 drawBac…

SpringMVC校验注解不生效

简介 SpringMVC框架提供了SPI扩展&#xff1a;javax.validation.spi.ValidationProvider&#xff0c;用来实现参数校验功能。Spring使用hibernate-validator作为它的默认实现&#xff0c;我们只需要进行一些简单的注解声明&#xff0c;就可以达到参数校验的功能。但是在实际使…

【网络安全|漏洞挖掘】ChatGPT 再曝安全漏洞,被指泄露私密对话

风靡全球的聊天机器人 ChatGPT 近日再次陷入安全风波&#xff0c;被曝泄露用户同机器人的私密对话&#xff0c;其中包含用户名、密码等敏感信息。 ArsTechnica 网站援引其读者提供的截图报道称&#xff0c;ChatGPT 泄露了多段非用户本人的对话内容&#xff0c;包含了大量敏感信…

前端入门第二天

目录 一、列表、表格、表单 二、列表&#xff08;布局内容排列整齐的区域&#xff09; 1.无序列表&#xff08;不规定顺序&#xff09; 2.有序列表&#xff08;规定顺序&#xff09; 3.定义列表&#xff08;一个标题多个分类&#xff09; 三、表格 1.表格结构标签 2.合并…

使用宝塔面板访问MySQL数据库

文章目录 前言一、安装访问工具二、查看数据库总结 前言 前面我们已经部署了前后端项目&#xff0c;但是却不能得到数据库的信息&#xff0c;看有谁再使用你的项目。例如员工、用户等等。本次博客进行讲解如何在宝塔面板里面访问MySQL数据库。 一、安装访问工具 1、打开软件商…

TensorFlow2实战-系列教程13:Resnet实战1

&#x1f9e1;&#x1f49b;&#x1f49a;TensorFlow2实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Jupyter Notebook中进行 本篇文章配套的代码资源已经上传 Resnet实战1 Resnet实战2 Resnet实战3 1、残差连接 深度学习中出现了随着网络的堆叠…

单例模式

如有错误或有补充&#xff0c;以及任何的改进意见&#xff0c;请在评论区留下您的高见&#xff0c;同时文中给出大部分的示例 如果觉得本文写的不错&#xff0c;不妨点个赞&#xff0c;收藏一下&#xff0c;助力博主产生质量更高的作品 概念 单例模式&#xff08;Singleton …

scienceplots绘图浅尝

前言 科研写作中&#xff0c;黑压压的文字里面如果能有一些优美的图片无疑会给论文增色不少&#xff0c;绘图的工具有很多&#xff0c;常用的有Excel、Python、Matlab等&#xff0c;Matlab在绘图方面相较于Python有一种更加原生的科研风&#xff0c;而且可视化编辑图例、坐标轴…