在Doctrine ORM中,persist()
和flush()
操作是分开的。看起来每当你想插入/更新你的实体时,你必须一个接一个地调用两个方法。大多数开发人员都是这样做的。但我想知道它是不是打算这样使用的。
大多数时候,我看到这样的仓库:
class EntityRepo extends ServiceEntityRepository
{
public function save(Entity $entity): void
{
$this->getEntityManager()->persist($entity);
$this->getEntityManager()->flush();
}
)
这种方法有一个很大的缺陷,即使把冗长放在一边-调用flush()
将同步所有未同步的实体与数据库,而不仅仅是我们现在保存的实体。我建议打电话给
$this->getEntityManager()->flush($entity);
将同步限制为仅一个实体,但这种方法已被Doctrine弃用。
在我的理解中,flush()
只在“业务事务”中被调用一次,它的职责是将所有内存中的更改与数据库同步。这很好地坚持了使域核心“纯净”任何副作用的“功能”思想:我们只是把所有的副作用移到域代码之外。我说错了吗?这种方法有什么缺点?
doctrine best practices和Ocramius都没有提到它。
处理flush()
的最佳实践是什么?
我尝试在每次调用persist()
时都调用flush()
,并在保存/更新不相关的实体时产生了不希望的副作用。我也试着在“业务事务”结束时调用flush()
一次,例如在Controller中,或者在Middleware中,但看起来这种方法不受欢迎,我担心我误解了一些东西。
2条答案
按热度按时间p1iqtdky1#
首先,您需要了解Doctrine使用“工作单元”模式和“标识Map”模式。https://martinfowler.com/eaaCatalog/unitOfWork.htmlhttps://martinfowler.com/eaaCatalog/identityMap.html
“原生”SQL连接存在一个问题,您可以在不同的时刻多次使用和更新同一实体,这可能会导致不同的问题。因此,教义使用许多不同的功能。:°
Doctrine使用flush来确保所有数据都是一次性管理的,正确更新,不丢失数据,不创建太长的事务。
你说得对,这是为了防止副作用。
要做到这一点,学说需要知道所有的实体,如果有存在于数据库等。这就是为什么要持久化一个新实体的原因。但是你也可以使用
merge
和unmerge
实体(要非常小心,因为它可能会导致数据丢失,或者数据不同步...)remove
等等... entityManage的实体加载是自动管理的,因此不需要合并主题,例如:)优点:
交易中最大的问题之一是你不能使用not commit对象,所以如果你有发票,你不能在插入发票之前支付。所以你不能用安全的数据来做这件事,如果你的程序抛出错误,你也不能避免改变。教条和冲洗解决这个问题!
在复杂的数据更改或处理中,它将帮助您减少SQL请求(更少的请求,有更好的性能…)
任何其他不太重要但有用的,如自动插入所有元素(不需要请求),“虚拟集合”的元素在多对多连接等…
的缺点
需要大量不同的元素,当我们使用不当时,很容易导致冲突
最后,冲水没有好的做法,随时使用它,你需要它。好的实践需要用于其他方法(persist、merge、unmerge、remove…),因为它们可能会产生难以解决的冲突(例如使用其他entityManager实体)
我希望我能回答你的问题:)
r1zhe5dt2#
你是正确的,在persist()的每个示例上调用flush()将被认为是一种反模式[1],但是你需要从Unit of Work的Angular 更广泛地考虑:
**单持久化到刷新的情况:**有时这个工作单元只是一个单持久化语句--比如创建一个用户,然后你就完成了这项工作,然后去做一些完全不同的事情。在这些情况下,是的,您将在persistent之后立即调用flush()。
**多个Persists to Flush情况:**当我们讨论包含多个任务的工作单元时,等待调用flush()就开始起作用了。例如,我可能会创建一个新公司,这会导致新对象,并为公司表、联系人表以及其他一些表创建数据库更新,所有这些都与向CRM添加新公司的“工作”有关。当持久化时,这些对象变得可用(可以说是在内存中),但尚未提交到数据库。当你使用flush()时,它会将所有内容持久化到数据库中(或者按照原则,它们与数据库同步)。
**Minimum Flush Interval:**Doctrine说你应该为一个HTTP请求设置0-2 flush()--这意味着你不应该为每个HTTP请求刷新多次,因为从概念上讲,一个HTTP请求由一个工作单元组成。而且它应该作为一个“单元”成功或失败。
从一个HTTP请求中删除十倍的刷新可能是危险的,因为这意味着你有持久化的数据,这些数据目前在ORM中可用,但如果它在以后的某个时间点从未刷新过,它可能会丢失。
**重叠工作:**虽然我想不出具体的情况,但似乎你可能在暗示你正在执行多个重叠工作,所以你只想刷新某些工作,而不是其他工作。这将为全局刷新的方法带来问题。但是,在特定HTTP请求的末尾(或者甚至在函数/类之外)有未刷新的数据可能是危险的。我可以想象你所描述的是一个更大的反模式,在开始一个新任务的同时,把未完成的工作留在table上。
[1]Persisting Document下的Official Doctrine文档-https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/working-with-objects.html#persisting-documents