darlinkster/

php-dynamodb-odm

DynamoDB 的 ODM

v0.7.4 2020-07-15 10:45 UTC

README

darlinkster/dynamodb-odm 是一个 ODM(对象数据映射)库,用于轻松使用 AWS 强大的键值数据库:DynamoDb。

注意:本文档假设您对 DynamoDB 有一定的了解,以及 DynamoDB 与传统 RDBMS(例如 MySQL)之间的区别。本文档中讨论的一些术语和概念是 DynamoDB 特有的,不会在本文档中解释。要学习 DynamoDB,请参阅官方开发指南

安装和配置

要获取 darlinkster/dynamodb-odm,您可以通过 composer 简单地要求它

$ composer require darlinkster/dynamodb-odm

类加载

DynamoDb ODM 的自动加载由 composer 处理。您只需将 composer 自动加载文件包含到项目中即可

<?php

require_once "vendor/autoload.php";

获取 ItemManager

一旦您准备好了类加载,您就可以获取一个 ItemManager 实例。ItemManager 类是库提供的 ODM 功能的主要访问点。

<?php
use Darlinkster\Mlib\ODM\Dynamodb\ItemManager;

$awsConfig     = [
    "profile" => "oasis-minhao",
    "region"  => "ap-northeast-1"
];
$tablePrefix   = "odm-";
$cacheDir      = __DIR__ . "/ut/cache";
$isDev         = true;
$itemNamespace = 'Darlinkster\Mlib\ODM\Dynamodb\Ut'; // in practice, this usually looks like: My\Root\Namespace\Items
$itemSrcDir    = __DIR__ . "/ut"; // in practice, this usually points to src/Items directory

$im = new ItemManager(
    $awsConfig,
    $tablePrefix,
    $cacheDir,
    $isDev
);
$im->addNamespace(
    $itemNamespace,
    $itemSrcDir
);

每个参数的解释如下

注意:Item 类定义了 ODM 管理的项目类型。一些典型的例子包括:User、Order、GameRoom 和 Card

设置命令行工具

DynamoDb ODM 随附了一些在开发过程中非常有帮助的命令行工具。您可以从 Composer 二进制目录中调用此命令

$ ./vendor/bin/oasis-dynamodb-odm

您需要将应用程序的 ItemManager 注册到控制台工具,以便使用内置命令。这可以通过在调用目录下创建一个包含以下内容的 odm-config.php 文件来完成

<?php
use Darlinkster\Mlib\ODM\Dynamodb\Console\ConsoleHelper;

// replace with file to your own project bootstrap
require_once 'bootstrap.php';

// replace with your own mechanism to retrieve the item manager
$itemManager = GetItemManager();

return new ConsoleHelper($itemManager);

更详细的使用方法请参见后面的部分

映射

ODM 库的基本功能是将对象模型(即类)映射到数据库结构。DynamoDb ODM 提供了一种方便的方法来使用注解来建立这种映射

<?php
use Darlinkster\Mlib\ODM\Dynamodb\Annotations\Field;
use Darlinkster\Mlib\ODM\Dynamodb\Annotations\Item;

/**
 * @Item(
 *     table="users",
 *     primaryIndex={"id"}
 * )
 */
class User
{
    /**
     * @var int
     * @Field(type="number")
     */
    protected $id;

    /**
     * @var string
     * @Field(type="string")
     */
    protected $name;
}

上面的类声明了一个简单的 User 模型,它将被映射到 DynamoDb 表 "users"(可能带有前缀)。下面的注释将进行解释

Item

您想使用 ODM 存储到数据库中的每个 PHP 对象都称为 "Item"。要描述一个对象作为项,我们必须描述这个对象的类。

使用 @Item 注释的类将由 ItemManager 管理。Item 接受以下属性

  • table:对象的表名
  • primaryIndex:主索引,可以是键数组或 @Index 注释对象
  • globalSecondaryIndices:全局次要索引数组;全局次要索引可以是键数组或 @Index 注释对象
  • localSecondaryIndices:本地次要索引数组;本地次要索引可以是键数组或 @Index 注释对象
  • repository:仓库类名;默认情况下,使用 \Darlinkster\Mlib\ODM\Dynamodb\ItemRepository
  • projected:此项是否仅投影。投影项不可更新(允许删除操作)。读取投影项(即获取/查询/扫描)时,仅从 DynamoDB 中获取此项的属性。

字段

将PHP类转换成Item之后,下一步是将该类的属性映射到DynamoDb中的属性。

我们使用@Field注解来描述类属性,这些属性是DynamoDb的属性。 @Field注解支持以下属性:

  • type:属性的类型,可以是以下之一
    • string(默认)
    • number
    • binary
    • bool
    • null
    • list
    • map
  • name:DynamoDb属性的名称,如果与属性名称不同。此值默认为null,表示属性键与属性名称相同。

分区哈希键

分区哈希键是查询中用作哈希键的字段的扩展。在某些情况下,您可能只想查询该字段的单个值(或非常少的值)。DynamoDB的性质只会利用分配的读取容量的一小部分,因此会限制您的系统性能。然而,通过使用该字段的分区哈希键,原始字段的每个值在分区哈希键字段中都将有一组映射值。通过并行查询这些分区值(参见多查询),在用例中的查询性能应该会显著提高。

我们使用@PartitionedHashKey注解来描述分区哈希键字段。支持的属性有:

  • baseField:原始字段名称
  • hashField:用作哈希源的值所在字段,始终使用分布良好的字段作为哈希字段(例如,项的唯一ID)
  • size:分区大小,默认为16

索引

在声明不同的索引时,我们可以使用@Index注解来使文档块更易于阅读。一个@Index由两个键组成:

  • hash:哈希键名称
  • range:范围键名称,如果此索引没有范围键,则留空
  • name:索引的名称,如果希望ODM为您自动生成一个,则留空。(注意:主索引不需要名称)

以下是我们向其中添加全局二级索引的User类声明:

/**
 * @Item(
 *     table="users",
 *     primaryIndex={"id"},
 *     globalSecondaryIndices={
 *         @Index(hash="class", range="age", name="class-age-gsi")
 *     }
 * )
 */
class User
{
    // ...

    /**
     * @var string
     * @Field()
     */
    protected $class;

    /**
     * @var int
     * @Field(type="number")
     */
    protected $age;
}

检查和设置

一个字段可以被声明为检查和设置字段,使用@Field注解的“cas”属性。

检查和设置字段是ODM使用的字段,以确保不会由于不同的工作者同时更新/插入单个项目而更新/插入项目超过一次。

"cas"属性值的可以是以下之一

  • disabled:这是默认值,具有“cas”禁用的字段在更新/插入项目时不会进行检查
  • enabled:在更新项目时将检查该字段的旧值。在插入项目时,此字段必须具有NULL值或不存在。
  • timestamp:这是启用cas属性的特殊类型。每次更新/插入项目时,此字段的值都将自动设置为当前时间戳。

注意:只有在调用ItemManger#flush()时才会进行检查和设置验证。如果未满足检查和设置条件,将抛出Darlinkster\Mlib\ODM\Dynamodb\Exceptions\DataConsistencyException异常。

与对象一起工作

ODM中管理所有对象(项目)。对象的操作类似于对象级事务。一旦对象被管理,无论是作为新对象持久化还是从数据库中获取,其管理状态都将存储在ItemManager中。对对象的任何更改都将记录在内存中。然后可以通过在ItemManager上调用ItemManager#flush()方法来提交对象更改。

可以通过调用 ItemManager#clear() 来手动清空 ItemManager。然而,尚未提交的任何更改都将丢失。

注意:理解这一点非常重要,只有 ItemManager#flush() 才会对数据库执行写入操作。其他任何方法,如 ItemManager#persist($item)ItemManager#remove($item),只是通知 ItemManager 在刷新时执行这些操作。如果不调用 ItemManager#flush(),则会导致请求期间的所有更改丢失。

持久化项目

可以通过传递给 ItemManager#persist($item) 方法使项目持久化。通过对某些项目应用持久化操作,该项目变为 MANAGED,这意味着其持久性现在由 ItemManager 管理。因此,在调用 ItemManager#flush() 时,此类项目的持久状态将随后与数据库进行正确同步。

示例

<?php
/** @var ItemManger $im */
$user = new User();
$user->setName('Mr.Right');
$im->persist($user);
$im->flush();

移除项目

可以通过传递给 ItemManager#remove($item) 方法从持久存储中移除项目。通过对某些项目应用移除操作,该项目变为 REMOVED,这意味着一旦调用 ItemManager#flush(),其持久状态将被删除。

示例

<?php
/** @var ItemManger $im */
/** @var User $user */
$im->remove($user);
$im->flush();

断开连接项目

可以通过在项目上调用 ItemManager#detach($item) 方法来将其从 ItemManager 断开连接,从而不再由它管理。断开连接的项目所做的更改(如果有的话,包括项目的移除),在项目断开连接后不会同步到数据库。

DynamoDb ODM 不会保留对断开连接项目的任何引用。

示例

<?php
/** @var ItemManger $im */
/** @var User $user */
$im->detach($user);
$user->setName('Mr.Left');
$im->flush(); // changes to $user will not be synchronized

与数据库同步

ItemManager 的 flush() 调用将在数据库上同步持久项的状态。同步涉及将任何对持久项的更新写入数据库。当调用 ItemManager#flush() 时,ODM 将检查所有受管理、新和已删除的项,并将执行以下操作:

  • 在数据库中创建新对象
  • 更新数据库中受管理项的更改属性
  • 从数据库中删除已删除的项目

获取项目

DynamoDb ODM 提供以下方式,按功能强大和灵活性的递增顺序,以获取持久对象。你应该始终从最简单且适合你需求的一个开始。

通过主索引

获取持久对象的最基本方式是通过其主索引使用 ItemManager#get($itemClass, $primayKeys) 方法。以下是一个示例

<?php
/** @var ItemManager $im */
$user = $im->get(User::class, ["id" => 1]);

返回值是找到的项目实例,或者如果无法找到给定标识符的实例,则为 null。

本质上,ItemManager#get() 只是以下内容的快捷方式

/** @var ItemManager $im */
/** @var ItemRepository $userRepo */
$userRepo = $im->getRepository(User::class);
$user = $userRepo->get(["id" => 1]);

通过可查询索引上的简单条件

要基于简单条件查询一个或多个项目,请使用存储库上的 ItemManager#query()ItemManager#queryAndRun() 方法,如下所示

/** @var ItemManager $im */
/** @var ItemRepository $userRepo */
$userRepo = $im->getRepository(User::class);
/** @var Users[] $users */
$users = $userRepo->query(
    "#class = :class AND #age >= :minAge",
    [
        ":class" => "A",
        ":minAge" => 25,
    ],
    "class-age-index"
);

注意:简单条件是只使用一个索引的条件。如果使用的索引包含 哈希键范围键,则只有在 哈希键 也出现在条件中时,才能使用 范围键。此外,只能对 哈希键 执行等于测试操作。

通过分区哈希键上的多查询

要基于分区哈希键查询一个或多个项目,请使用存储库上的 ItemManager#multiQueryAndRun() 方法,如下所示

/** @var ItemManager $im */
/** @var ItemRepository $userRepo */
$userRepo = $im->getRepository(User::class);
/** @var Users[] $users */
$users = $userRepo->multiQueryAndRun(
    function ($item) {
        // each item returned can be accessed here in the callback
    },
    "classPartition", // PartitionedHashKey field name
    "A", // value expected in the base field (not the partition field)
    "#age >= :minAge", // only range conditions here
    [
        ":minAge" => 25,
    ],
    "class-partition-age-index" // index for PartitionedHashKey
);

通过非可查询索引上的过滤器

要查询没有关联索引的一个或多个项目,请使用存储库上的 ItemManager#scan()ItemManager#scanAndRun() 方法,如下所示

/** @var ItemManager $im */
/** @var ItemRepository $userRepo */
$userRepo = $im->getRepository(User::class);
/** @var Users[] $users */
$users = $userRepo->scan(
    "#class = :class AND #age >= :minAge AND #name = :name",
    [
        ":class" => "A",
        ":minAge" => 25,
        ":name" => "John",
    ],
);

使用命令行工具

DynamoDb ODM 一起提供了可执行工具和库。安装后,有以下构建命令可以帮助您管理项目数据库模式:

创建

$ ./vendor/bin/oasis-dynamodb-odm odm:schema-tool:create

创建命令将遍历所有管理的项目并相应地创建表。所有主索引、LSI 和 GSI 也会被创建。

注意:如果同前缀下已经存在相同名称的表,将抛出异常。在这种情况下,不会创建任何表。

注意:如果您想跳过创建现有表(即仅创建不存在的表),可以使用 “--skip-existing-table” 选项

更新

$ ./vendor/bin/oasis-dynamodb-odm odm:schema-tool:update

更新命令实际上是创建命令的一个更强大(但也更慢)版本。它会检查所有管理项目,并在表不存在时创建表。此外,如果表存在但定义了不同的 GSI,更新命令将相应地更新 GSI。

注意:由于 DynamoDb 的特性,在表创建后无法更新主索引或 LSI。在开发环境中,建议在需要时删除表并重新创建。

注意:如果您只想查看数据库模式的变化而不执行实际更新,可以在命令行中指定 “--dry-run” 选项。程序将仅提示可能的变化而不实际执行。

删除

$ ./vendor/bin/oasis-dynamodb-odm odm:schema-tool:drop

删除命令将删除与所有管理项目关联的所有表。**不要**在生产环境中运行此命令!