littlegiant / silverstripe-batchwrite
用于silverstripe数据对象的批量写入
Requires
- silverstripe/cms: >=3.0
- silverstripe/framework: >=3.0
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)
按类别分组数据对象,然后使用每个类别/表的查询删除对象。这不会调用onBeforeDelete
或onAfterDelete
。也不会删除子对象,例如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)
,这不会调用任何onBeforeDelete
或onAfterDelete
。这可以用来避免填充即将被删除的数据对象。
$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
这增加了onBeforeWriteCallback
、onAfterWriteCallback
和onAfterExistsCallback
。
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);
}
想要贡献或需要其他功能?
贡献总是受欢迎的,请创建一个拉取请求,我会在有空的时候进行审查和合并。如果您有新的功能请求或建议,请创建一个问题,我会调查它!