Типичное нарушение ACID в symfony проекте
Столкнулся с частым явлением нарушения ACID в symfony проекте.
public function batchCreate(
PurchaseOrder $purchaseOrder,
array $nomenclatures,
AdUser $attachingUser
): void {
$this->em->beginTransaction();
try {
foreach ($nomenclatures as $nomenclature) {
$this->createOrIncreaseQuantity(
$purchaseOrder->getId(),
$nomenclature->getId(),
$nomenclature->getQuantity(),
$attachingUser
);
}
$this->recalculateFactAmountForPurchaseOrder($purchaseOrder->getId());
$this->purchaseOrderDocumentAmountService->recalculateAllDocumentWithOutDiscrepancy($purchaseOrder);
$this->em->commit();
} catch (Throwable $e) {
$this->em->rollBack();
throw $e;
}
$this->producer->send(new PurchaseOrderUpdatedAsyncMessage($purchaseOrder->getId()), $purchaseOrder->getGuid());
}
На высоко нагруженном проекте в данной функции будут регулярно возникать самые разные интересные ошибки. Возможно программист писавший это был окрылен php 7.3 или не понимал, что творит. А возможно эта функция деградировала вместе с кодовой базой.
Так что так?
А начало транзакции с участием объекта извне. $purchaseOrder
может существовать как объект, но уже не быть как запись в СУБД.
Правильно в этом случает в функцию передать $purchaseOrderId
и уже внутри получить $purchaseOrder
для манипуляций.
Должно получиться, что-то типа
public function batchCreate(
int $purchaseOrderId,
array $nomenclatures,
AdUser $attachingUser
): void {
$this->em->beginTransaction();
try {
$purchaseOrder = $this->purchaseOrderRepository->find($purchaseOrderId);
if (!$purchaseOrder) {
throw new InvalidArgumentException("Данной закупки уже нет");
}
foreach ($nomenclatures as $nomenclature) {
$this->createOrIncreaseQuantity(
$purchaseOrder->getId(),
$nomenclature->getId(),
$nomenclature->getQuantity(),
$attachingUser
);
}
$this->recalculateFactAmountForPurchaseOrder($purchaseOrder->getId());
$this->purchaseOrderDocumentAmountService->recalculateAllDocumentWithOutDiscrepancy($purchaseOrder);
$this->em->commit();
$this->producer->send(new PurchaseOrderUpdatedAsyncMessage($purchaseOrder->getId()), $purchaseOrder->getGuid());
} catch (Throwable $e) {
$this->em->rollBack();
throw $e;
}
}
Written on July 3, 2022