littlegiant/silverstripe-batchwrite

用于silverstripe数据对象的批量写入

安装数: 8,037

依赖者: 1

建议者: 0

安全性: 0

星标: 4

关注者: 1

分支: 5

类型:silverstripe模块

0.3.0 2015-12-21 01:23 UTC

This package is auto-updated.

Last update: 2024-08-27 15:42:13 UTC


README

批量写入数据对象以提升批量插入/更新/删除的性能。目前仅支持MySQL,并且仅在使用mysqli适配器时。

基本用法

$batch = new Batch();

$objects = ...;
$batch->write($objects);

$versionedObjects = ...;
$batch->writeToStage($versionedObjects, 'Stage');

$objectsToDelete = ...;
$batch->delete($objectsToDelete);

$versionedObjectsToDelete = ...;
$batch->deleteFromStage($versionedObjectsToDelete, 'Stage');

$class = 'DataObjectClass';
$ids = array(1, 2, 3...)
$batch->deleteIDs($class, $ids);

$class = 'VersionedClass';
$batch->deleteIDsFromStage($versionedClass, $ids);

write($dataObjects)

按类别分组数据对象,然后使用一个查询插入/更新对象。这将调用onBeforeWrite()onAfterWrite()。它还会填充新数据对象的ID

$batch = new Batch();
$batch->write($objects);

writeToStage($dataObjects, $stage...)

write($dataObjects)相同,但允许您指定要写入的扩展Versioned对象的阶段。您可以传递多个阶段。例如 -

$batch = new Batch();
$batch->writeToStage($objects, 'Stage'); # writes to the 'Stage'
$batch->writeToStage($objects, 'Live'); # writes to 'Live' e.g publish()
$batch->writeToStage($objects, 'Stage', 'Live'); # writes to 'Stage' and 'Live'

writeManyMany($sets)

写入许多许多关系,其中$sets是一个包含"$set"的数组。每个$set是一个array($object, $relation, $belongsObject)。这不会检查关系是否已存在,并再次添加它

# team->many_many = array('TeamMembers' => 'Person')
# person->belongs_many_many = array('Teams' => 'Team')
$batch = new Batch();
$team = new Team();
$person = new Person();

$batch->write($team);
$batch->write($person);
$sets = array();
$sets[] = array($team, 'TeamMembers', $person);
$batch->writeManyMany($sets);

delete($dataObjects)

按类别分组数据对象,然后使用每个类别/表的查询删除对象。这不会调用onBeforeDeleteonAfterDelete。也不会删除子对象,例如SiteTree->Children()将变成孤儿。版本表也将不会更新。

$objects = DataObjectClass::get();
$batch = new Batch();
$batch->delete($batch);

deleteFromStage($dataObjects, $stage...)

delete($dataObjects)相同,但增加了删除版本对象的支持。您可以一次传递多个阶段。

$objects = VersionedObject::get();
$batch = new Batch();
$batch->deleteToStage($objects, 'Stage'); # deletes from the 'Stage'
$batch->deleteToStage($objects, 'Live'); # deletes from 'Live' e.g doUnpublish()
$batch->deleteToStage($objects, 'Stage', 'Live'); # deletes from 'Stage' and 'Live'

deleteIDs($className, $ids)

删除具有给定$ids$className的数据对象。根据delete($objects),这不会调用任何onBeforeDeleteonAfterDelete。这可以用来避免填充即将被删除的数据对象。

$className = 'DataObjectClass';
$ids = $className::get()->column('ID');
$batch = new Batch();
$batch->deleteIDs($className, $ids);

deleteIDsFromStage($className, $ids, $stage...)

deleteIDs相同,但允许您指定要从中删除的阶段。例如 -

$className = 'VersionedDataObjectClass';
$ids = $className::get()->column('ID');
$batch = new Batch();
$batch->deleteIDsFromStage($className, $ids, 'Stage'); # deleted from 'Stage'
$batch->deleteIDsFromStage($className, $ids, 'Live'); # deleted from 'Live'
$batch->deleteIDsFromStage($className, $ids, 'Stage', 'Live'); # 'Stage' and 'Live'

通过BatchedWriter进行批量抽象

BatchedWriter类允许您一次传递一个数据对象,当批量达到指定大小时,然后进行写入。下面的代码将每次写入100个对象,剩余的50个对象将在调用finish()时写入。

$writer = new BatchedWriter(100);

for ($i = 0; $i < 350; $i++) {
    $object = new DataObjectClass();
    $writer->write($object);
}

$writer->finish();

方法

BatchedWriter类具有与Batch相同的函数,但将第一个参数中的$objects替换为$object。应该调用finish()方法来写入/删除剩余的对象。

$writer = new BatchedWriter();

$writer->write($object);
$writer->writeToStage($object, $stage...);

$writer->delete($object);
$writer->deleteFromStage($object, $stage...);

$writer->deleteIDs($className, $id);
$writer->deleteFromStage($className, $id, $stage...);

$writer->finish(); # write/delete all the remaining objects

最大区别是writeManyMany($object, $relation, $belongsObjects)

$writer = new BatchedWriter();
$team = new Team();
$person1 = new Person();
$person2 = new Person();

$writer->write(array($team, $person1, $person2));

$afterExists = new OnAfterExists(function () use ($team, $person1, $person2, $writer) {
    $writer->writeManyMany($team, 'TeamMembers', array($person1, $person2));
});
$afterExists->addCondition($team);
$afterExists->addCondition($person1);
$afterExists->addCondition($person2);

$writer->finish();

处理has_one、has_many和many_many

为了减少写入次数并帮助抽象正确写入对象顺序的复杂性,可以在DataObject中通过WriteCallbackExtesion添加一些辅助方法。

---
Name: mysite-confg
---

...

DataObject:
    extensions:
        - WriteCallbackExtension

这增加了onBeforeWriteCallbackonAfterWriteCallbackonAfterExistsCallback

has_one

$writer = new BatchedWriter();

$team = new Team(); # has_one = array('Leader' => 'TeamLeader')
$team->Title = 'Team Spot';

$leader = new TeamLeader();
$leader->Name = 'Big Red';

$leader->onAfterExistsCallback(function ($leader) use ($writer, $team) {
    $team->LeaderID = $leader->ID;
    # write team when leader has been written
    $writer->write($team);
});

# write leader first
$writer->write($leader);
...
$writer->finish();

为了支持多个has_one对象,可以使用OnAfterExists

$writer = new BatchedWriter();
$object = new Object(); # has_one = array('HasOne1', 'HasOne2')
$hasOne1 = new HasOne1();
$hasOne2 = new HasOne2();

# create onAfterExists to write $object when conditions are met
$afterExists = new OnAfterExists(function () use ($writer, $object) {
    $writer->write($object);
});

# add condition that hasOne1 exists
$afterExists->condition($hasOne1, function ($hasOne1) use ($object) {
    $object->HasOne1 = $hasOne1->ID;
});

# add condition that hasOne2 exists
$afterExists->condition($hasOne2, function ($hasOne2) use ($object) {
    $object->HasOne2 = $hasOne2->ID;
});

# write has_ones
$writer->write($hasOne1);
$writer->write($hasOne2);
...
$writer->finish();

has_many

类似地,使用onAfterExistsCallback写入has_many对象

$writer = new BatchedWriter();

$team = new Team(); # has_many = array('TeamMembers' => 'TeamMember')

for ($i = 0; $i < 10; $i++) {
    $member = new TeamMember(); # has_one = array('Team' => 'Team');
    $team->onAfterExistsCallback(function ($team) use ($member, $writer) {
        $member->TeamID = $team->ID;
        $writer->write($team);
    });
}

$writer->write($team);
$writer->finish();

many_many

使用OnAfterExists等待所有对象都存在后再写入关系

$writer = new BatchedWriter();
$team = new Team();
$person1 = new Person();
$person2 = new Person();

$writer->write(array($team, $person1, $person2));

# see below
$afterExists = new OnAfterExists(function () use ($team, $person1, $person2, $writer) {
    $writer->writeManyMany($team, 'TeamMembers', array($person1, $person2));
});
$afterExists->addCondition($team);
$afterExists->addCondition($person1);
$afterExists->addCondition($person2);

$writer->finish();

榨取更多性能

Silverstripe 数据对象和扩展功能非常强大。但伴随这种强大的功能,也带来了巨大的开销。一种容易避免的开销是实例化一个新的数据对象。为了避免为大量对象执行相同的代码,创建单个实例然后多次克隆会更有效率。这可以通过 QuickDataObject 类轻松实现。警告:这只会调用构造函数一次,不要在需要为每个实例执行构造函数的情况下使用

$className = 'SomeDataObject';
for ($i = 0; $i < 1000; $i++) {
    $object = QuickDataObject::create($className);
}

想要贡献或需要其他功能?

贡献总是受欢迎的,请创建一个拉取请求,我会在有空的时候进行审查和合并。如果您有新的功能请求或建议,请创建一个问题,我会调查它!