andrewdalpino/dataloader-php 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

andrewdalpino/dataloader-php

Composer 安装命令:

composer require andrewdalpino/dataloader-php

包简介

A speed layer that enables batch loading, de-duplication, and caching for efficient data fetching over any storage backend.

README 文档

README

A thin caching and data access layer that goes over your existing storage layer and infrastructure. DataLoader PHP uses buffering and cache memoization to optimize requests to the storage layer, prevent overfetching, and prevent N+1 access pattern issues. Based on the Facebook Javascript reference implementation.

Features

  • Fast in-memory buffering, deduplication, and memoization out of the box
  • Simple, lightweight, and no dependencies
  • Storage layer agnostic (use with Redis, MySQL, MongoDB, a REST endpoint, anything you want)

Installation

Install DataLoader PHP using composer:

composer require andrewdalpino/dataloader-php

Getting Started

First, you need to create a batch function that will perform the duty of fetching the buffered entities from storage (Redis, REST endpoint, etc.) when necessary. The batch function takes an array of buffered keys as its only argument and must return an array or iterable object.

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

Optionally, you can specify a cache key function that tells DataLoader how to key the loaded entities. The cache key function takes the $entity to be keyed as an argument as well as its index in the returned array. If you do not specify a cache key function then DataLoader will attempt to use $entity->id, $entity['id'], or fallback to the index of the returned array.

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

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

Example

The following is an example of how you could build a User loader in Laravel using an Eloquent model as the fetching 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);

Usage

First you must buffer the keys of the entities you wish to load in the future by calling the batch method on the DataLoader object. The batch() function takes either a single integer or string $key or an array of $keys and will tell DataLoader to hold them in the buffer until the next load() operation is called.

$userLoader->batch(1);

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

It is important to call batch() on every entity you plan to load during the request cycle. DataLoader will not make additional requests to the storage backend if the keys are not in the buffer.

Once you have finished the batching stage, you may call load() to load the entities by key. The load() and loadMany() methods take a single $key or an array of $keys and return a single entity or an array of entities respectively.

$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.

Example

The following example demonstrates how DataLoader could be used in a Webonyx GraphQL resolve function paired with the Webonyx Deferred mechanism to fulfill GraphQL queries. In this example, imagine that the user loader has been built and injected via an application container and accessed by its UserLoader facade.

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);
                });
            }
        ],
    ],
]);

In this example, whenever the author field on a Post node is requested in a GraphQL query, the UserLoader will batch the user entity supporting that data, and then wait until the resolvers have all been called to fetch the data via the Deferred callback. It is clearer to see how we avoid any N+1 access pattern issues by employing this mechanism.

Loading entities from outside of the batch function

Sometimes, the batch function is not the most efficient route to accessing a particular entity. Under other circumstances, such as non-primary key lookups, it's just not possible.

When you need to load an entity into the cache from another source, other than the batch function, you may do so by calling the prime() method on the data loader instance. The prime() method takes an $entity to be primed as an argument. Each primed entity will be keyed by the same cache key function as the ones loaded with the batch function.

$friend = User::find(1);

$userLoader->prime($friend);

Flushing the cache

You may flush the entire in-memory cache by calling the flush() method on the cache instance.

$userLoader->flush();

Runtime Configuration

You can tweak the runtime performance of DataLoader by supplying an array of options as the third parameter to the constructor. The options available are listed below with their default values.

$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);

Requirements

  • PHP 7.1.3 or above

License

MIT

andrewdalpino/dataloader-php 适用场景与选型建议

andrewdalpino/dataloader-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 9.21k 次下载、GitHub Stars 达 10, 最近一次更新时间为 2018 年 03 月 18 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「database」 「php」 「memoization」 「graphql」 「dataLoader」 「deduplication」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 andrewdalpino/dataloader-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 andrewdalpino/dataloader-php 我们能提供哪些服务?
定制开发 / 二次开发

基于 andrewdalpino/dataloader-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 9.21k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 10
  • 点击次数: 35
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 10
  • Watchers: 1
  • Forks: 2
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-03-18