andrewdalpino/dataloader-php

一个快速层,可以为任何存储后端提供批加载、去重和缓存,以实现高效的数据获取。

v1.0.3 2018-02-28 04:30 UTC

This package is auto-updated.

Last update: 2024-09-18 19:04:04 UTC


README

一个轻量级的缓存和数据访问层,它位于您现有的存储层和基础设施之上。DataLoader PHP 通过缓冲和缓存记忆优化对存储层的请求,防止过度获取,并防止 N+1 访问模式问题。基于 Facebook Javascript 引用实现

功能

  • 开箱即用的快速内存缓冲、去重和记忆化
  • 简单、轻量级且无依赖
  • 存储层无关(可以与 Redis、MySQL、MongoDB、REST 端点等一起使用)

安装

使用 composer 安装 DataLoader PHP

composer require andrewdalpino/dataloader-php

入门

首先,您需要创建一个批处理函数,当需要时,该函数将从存储(Redis、REST 端点等)中提取缓存的实体。批处理函数只接受一个包含缓冲键的数组作为其唯一参数,并且 必须 返回一个数组或可迭代对象。

$batchFunction = function ($keys) {
    return Redis::mget(...$keys);
};
$loader = new BatchingDataLoader($batchFunction);

可选地,您可以指定一个缓存键函数,该函数告诉 DataLoader 如何对加载的实体进行键控。缓存键函数接受要键控的 $entity 作为参数以及它在返回数组中的索引。如果您未指定缓存键函数,则 DataLoader 将尝试使用 $entity->id$entity['id'] 或回退到返回数组的索引。

$cacheKeyFunction = function ($entity, $index) {
    return $entity['id'];
};

$loader = new BatchingDataLoader($batchFunction, $cacheKeyFunction);

示例

以下是一个示例,说明您如何在 Laravel 中使用 Eloquent 模型作为提取 API 来构建用户加载器。

use AndrewDalpino\DataLoader\BatchingDataLoader;
use App\User;

// Required batch function to load users with supplied array of buffered $keys.
$batchFunction = function ($keys) {
    return User::findMany($keys);
};

// Optional cache key function returns the primary key of the user entity.
$cacheKeyFunction = function ($user, $index) {
    return $user->id;
};

$userLoader = new BatchingDataLoader($batchFunction, $cacheKeyFunction);

使用方法

首先,您必须通过在 DataLoader 对象上调用批处理方法来缓冲您希望在将来加载的实体的键。批处理函数接受单个整数或字符串 $key$keys 的数组,并告诉 DataLoader 将它们保留在缓冲区中,直到下一次调用 load() 操作。

$userLoader->batch(1);

$userLoader->batch([1, 2, 3, 4, 5]);

在请求周期中,您必须对计划加载的每个实体调用 batch()。如果键不在缓冲区中,DataLoader 不会 对存储后端进行额外的请求。

一旦完成批处理阶段,您可以调用 load() 来按键加载实体。load()loadMany() 方法分别接受单个 $key$keys 的数组,并分别返回单个实体或实体数组。

$userLoader->batch(['a', 'b', 'c', 'd', 'e']);

$user = $userLoader->load('a'); // Returns the user with primary key 'a'.

$users = $userLoader->loadMany(['b', 'c', 'd', 'e']); // Returns an array of users.

$users = $userLoader->loadMany(['b', 'c']); // Additional loads don't hit the database.

$user = $userLoader->load('z'); // Returns null.

$users = $userLoader->loadMany(['y', 'z']); // Return an empty array.

示例

以下示例演示了如何将 DataLoader 与 Webonyx Deferred 机制一起用于 Webonyx GraphQL 解析函数,以满足 GraphQL 查询。在这个例子中,想象用户加载器已经被构建并通过应用程序容器注入,并通过其 UserLoader 门面访问。

use GraphQL\Type\Definition\ObjectType;
use GraphQL\Deferred;
use UserLoader;

$postType = new ObjectType([
    'fields' => [
        'author' => [
            'type' => 'UserNode',
            'resolve' => function($post) {
                UserLoader::batch($post->author_id);

                return new Deferred(function () use ($post) {
                    return UserLoader::load($post->author_id);
                });
            }
        ],
    ],
]);

在这个例子中,每当在 GraphQL 查询中请求 Post 节点的 author 字段时,UserLoader 将批量处理支持该数据的用户实体,然后等待所有解析器被调用,通过 Deferred 回调获取数据。通过采用此机制,我们可以更清楚地看到如何避免任何 N+1 访问模式问题。

从批处理函数外部加载实体

有时,批量函数并不是访问特定实体的最高效方法。在其他情况下,例如非主键查找,这可能根本不可能。

当您需要从除批量函数以外的其他来源将实体加载到缓存中时,可以通过在数据加载器实例上调用prime()方法来实现。该prime()方法接受一个用于预充的$entity作为参数。每个预充的实体都将使用与批量函数加载的实体相同的缓存键函数进行索引。

$friend = User::find(1);

$userLoader->prime($friend);

刷新缓存

您可以通过在缓存实例上调用flush()方法来刷新整个内存缓存。

$userLoader->flush();

运行时配置

您可以通过将选项数组作为构造函数的第三个参数提供,来调整DataLoader的运行时性能。以下列出了可用的选项及其默认值。

$options = [
    'batch_size' => 1000 // The max number of entities to batch load in a single round trip from storage.
];

$loader = new BatchingDataLoader($batchFunction, $cacheKeyFunction, $options);

需求

  • PHP 7.1.3或更高版本

许可证

MIT