spatie/laravel-queued-db-cleanup

安全删除大量记录

资助包维护!
spatie

安装: 126,516

依赖者: 1

建议者: 0

安全: 0

星标: 78

关注者: 5

分支: 10

1.4.0 2024-03-08 13:00 UTC

This package is auto-updated.

Last update: 2024-09-08 13:58:07 UTC


README

Latest Version on Packagist Tests Total Downloads

使用 Laravel 一次性删除大量数据库记录存在一些需要注意的陷阱

  • 删除记录可能是一个耗时的操作,可能需要很长时间
  • 删除查询将获取许多行锁,并可能锁定整个表,其他查询将需要等待
  • 即使在管理查询执行和清理时,在无服务器环境中也存在一个固定的最大执行时间

这些陷阱在 这篇博客文章 中有更详细的描述,该文章发布在 Flare 博客 上。

此包提供了一种安全删除大量记录的解决方案。以下是一个示例

Spatie\LaravelQueuedDbCleanup\CleanDatabaseJobFactory::new()
    ->query(YourModel::query()->where('created_at', '<',  now()->subMonth()))
    ->deleteChunkSize(1000)
    ->dispatch();

上面的代码将调度一个清理作业,该作业将删除由查询选择的第一个1000条记录。当它检测到已删除1000条记录时,它将得出结论,可能并非所有记录都已删除,然后重新调度自身。

我们还将确保此清理作业从不重叠。这样就可以保持数据库连接数低。这也允许您通过 CRON 重复安排此清理作业,而无需检查是否存在现有的清理进程。

通过保持块大小小,查询执行得更快,潜在的表锁定时间不会很长。清理作业也会很快完成,因此您不会遇到执行时间限制。

支持我们

我们投入了大量资源来创建 一流的开放源代码包。您可以通过 购买我们的付费产品之一 来支持我们。

我们非常感谢您从家乡寄给我们明信片,说明您正在使用我们的哪个包。您可以在 我们的联系页面 上找到我们的地址。我们将在 我们的虚拟明信片墙上 发布所有收到的明信片。

安装

您可以通过 composer 安装此包

composer require spatie/laravel-queued-db-cleanup

此包使用锁来防止同一查询的多次删除同时执行。我们建议使用 Redis 存储锁。

在幕后,此包利用了 作业批处理。请确保您已创建了 Laravel 文档中提到的批次表。

可选地,您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="Spatie\LaravelQueuedDbCleanup\LaravelQueuedDbCleanupServiceProvider" --tag="config"

这是发布配置文件的内容

return [
    /*
     * To make sure there's only one job of a particular cleanup running,
     * this package uses a lock. Here, you can configure the default
     * store to be used by the lock and the release time.
     */
    'lock' => [
        'cache_store' => 'redis',

        'release_lock_after_seconds' => 60 * 20
    ],

    /*
     * The class name of the job that will clean that database.
     *
     * This should be `Spatie\LaravelQueuedDbCleanup\Jobs\CleanDatabaseJob`
     * or a class that extends it.
     */
    'clean_database_job_class' => Spatie\LaravelQueuedDbCleanup\Jobs\CleanDatabaseJob::class,

    /*
     * In order to handle deadlocks on a high traffic table, the package can
     * automatically retry the transaction that performs the delete query
     * a specified number of times
     */
    'delete_query_attempts' => 3,
];

用法

此代码将调度一个清理作业,该作业将删除由查询选择的第一个1000条记录。当它检测到已删除1000条记录时,它将得出结论,可能并非所有记录都已删除,然后重新调度自身。

Spatie\LaravelQueuedDbCleanup\CleanDatabaseJobFactory::new()
    ->query(YourModel::query()->where('created_at', '<',  now()->subMonth()))
    ->deleteChunkSize(1000)
    ->dispatch();

当删除的记录数少于 deleteChunkSize 给定的数量时,作业不会重新调度自身。

在计划任务中启动清理

可以在计划任务中安全地启动清理过程。内部,该包将使用锁来确保同时没有两个使用相同查询的清理过程在运行。

如果在另一个清理过程仍在运行时计划任务启动清理过程,则新的清理过程将被取消。

自定义队列和连接名称

内部,该包使用作业批次。使用 getBatch 可以获取批次并在其上调用如 onConnectiononQueue 的方法。别忘了在最后通过调用 dispatch() 来分发批次。

Spatie\LaravelQueuedDbCleanup\CleanDatabaseJobFactory::new()
    ->query(YourModel::query()->where('created_at', '<',  now()->subMonth()))
    ->deleteChunkSize(1000)
    ->getBatch()
    ->onConnection('redis')
    ->onQueue('cleanups')
    ->dispatch();

自定义数据库连接

使用 onDatabaseConnection 允许您在另一个连接上删除记录。

Spatie\LaravelQueuedDbCleanup\CleanDatabaseJobFactory::new()
    ->query(YourModel::query())
    ->onDatabaseConnection('other_connection')
    ->deleteChunkSize(1000)
    ->dispatch();

手动停止清理过程

默认情况下,当检测到已删除的记录数少于块大小时,清理作业将不会再次重新调度自己。您可以通过调用 stopWhen 来自定义此行为。它应接收一个闭包。如果闭包返回 true,则清理将停止。

CleanDatabaseJobFactory::forQuery(YourModel::query())
    ->deleteChunkSize(10)
    ->stopWhen(function (Spatie\LaravelQueuedDbCleanup\CleanConfig $config) {
        return $config->pass === 3;
    })
    ->dispatch();

stopWhen 接收一个 Spatie\LaravelQueuedDbCleanup\CleanConfig 实例。它包含这些属性以确定是否停止清理

  • pass:包含清理作业为此特定清理启动的次数。
  • rowsDeletedInThisPass:本次遍历中删除的行数
  • totalRowsDeleted:所有遍历中删除的总行数。

使用批次停止清理过程

您可以使用批次 ID 来停止清理过程。

$batch = CleanDatabaseJobFactory::forQuery(YourModel::query())
    ->deleteChunkSize(10)
    ->getBatch();

// you could store this batch id somewhere
$batchId = $batch->id;

$batch->dispatch();

在代码库的另一个地方,您可以检索存储的批次 ID 并使用它来取消批次,从而停止清理过程。

\Illuminate\Support\Facades\Bus::findBatch($batchId)->cancel();

事件

您可以监听这些事件。它们都有一个公共属性 cleanConfig,它是 Spatie\LaravelQueuedDbCleanup\CleanConfig 的一个实例。

Spatie\LaravelQueuedDbCleanup\Events\CleanDatabasePassStarting

在清理过程中启动新遍历时触发。

Spatie\LaravelQueuedDbCleanup\Events\CleanDatabasePassCompleted

在清理过程中完成遍历时触发。

Spatie\LaravelQueuedDbCleanup\Events\CleanDatabaseCompleted

在完成整个清理过程时触发。

测试

composer test

变更日志

请参阅 CHANGELOG 了解最近更改的更多信息。

贡献

请参阅 CONTRIBUTING 了解详细信息。

安全漏洞

请参阅我们如何报告安全漏洞的 安全策略

鸣谢

许可

MIT 许可证 (MIT)。请参阅 许可文件 了解更多信息。