ORM Doctrine, souběžný přístup

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Relapse
Člen | 34
+
0
-

Dobrý den,
prosím vás, řeší nějak doctrine souběžný přístup k položkám v databázi?

Mám konkrétní příklad:

	$product = $this->products->getProduct($id);

	$product->quantity -= $orderQuantity;

	$this->em->flush();

Jednoduše odečítám zásoby ze skladu.

Může dojít k situaci, kdy načtu z databáze objekt ‚Product‘ s hodnotou parametru ‚quantity = 100‘.
Ale než se její změna uloží ‚em->flush()‘, někdo jiný odečte a uloží např. 10. Takže správná hodnota v databázi ted bude 90, ale já mám načteno 100 a od této hodnoty budu odečítat.

Musím si takovou situaci ošetřit sám, nebo se o to nějakým způsobem stará doctrine?

Děkuji za pomoc.

Ot@s
Backer | 476
+
0
-

Doctrine neznám, nicméně koukni do generovaných SQL. Pokud jsou zabalené v transakcích, tak nemusíš nic řešit. Pokud ne, tak si je tam přidej. Možná najdeš něco užitečného zde.

enumag
Člen | 2118
+
0
-

@Ot@s Nemáš tak docela pravdu, může záležet na nastaveném TRANSACTION ISOLATION LEVEL. Doctrine sice všechno balí do transakcí, ale už jsem se setkal i s případem kdy to nestačilo právě kvůli nedostatečné izolaci.

Editoval enumag (9. 2. 2015 10:27)

Relapse
Člen | 34
+
0
-

Zatím to mám udělané následovně:

	$this->em->getConnection()->beginTransaction()
	try {
		//pesimistické zamykání
		//znemožní konkurenčním procesům číst a aktualizovat tyto záznamy
		$product = $this->products->getProduct($id, DoctrineDBALLockMode::PESSIMISTIC_WRITE);
		$product->quantity -= $orderQuantity;
		$this->em->flush();
		$this->em->getConnection()->commit();
	} catch (Exception $e) {
		$this->em->getConnection()->rollback();
		$this->em->close();
		throw $e;
	}

Zámek se odemkne po úspěšném volání COMMIT()?.

Jednoduše zamknu záznam Product, změním co potřebuji a odemknu, ať si ho může měnit zase někdo jiný.

V doctrine s tímto pracuji poprvní, tak mi prosím vás řekněte, jestli jsem se vydal správným směrem.
Děkuji

Editoval Relapse (9. 2. 2015 10:49)

llook
Člen | 407
+
0
-

Vydal jsi se správným směrem. Doctrine ORM sama od sebe do transakce uzavírá jenom flush.

Případně to zabal do transactional:

$this->em->getConnection()->transactional(function () {
	$product = $this->products->getProduct($id, DoctrineDBALLockMode::PESSIMISTIC_WRITE);
	$product->quantity -= $orderQuantity;
	$this->em->flush();
});
enumag
Člen | 2118
+
+3
-

@llook Trochu ti to zkrátím:

$this->em->transactional(function () {
    $product = $this->products->getProduct($id, DoctrineDBALLockMode::PESSIMISTIC_WRITE);
    $product->quantity -= $orderQuantity;
});