John Davidson

php - Doctrine not updating properly entity data with several concurrent requests

0 comments
Message:


I need to do something basic, I have two entities: User and Action. Each User has X tokens assigned by the Admin and then he can perform Y actions based on the amount of tokens. So lets say one User only has enough tokens to perform one Action, I identified that if I perform multiple simultaneously requests at the same exact time (like 5 or more requests at the same time). Instead of just one Action, the User executes two or more Actions (and only in the explained scenario, in the rest everything works fine)


The related code to my explanation:


public function useractions(Requests $request){
$user = $this->getUser();
$post = Request::createFromGlobals();
if($post->request->has('new_action') && $this->isCsrfTokenValid("mycsrf", $post->request->get('csrf_token'))) {
$entityManager = $this->getDoctrine()->getManager();
$tokens = $user->getTokens();

if($tokens<1){
$error = "Not enough tokens";
}
if(empty($error)){
$user->setTokens($tokens-1);
$entityManager->flush();
$action = new Action();
$action->setUser($user);
$entityManager->persist($transaction);
$entityManager->flush();
}
}
}

And I am using mariadb 10.5.12 with InnoDB as the engine


Obviously I am making a big mistake in my code or missing something in the Symfony or Doctrine configuration. Someone could tell me the mistake? Thanks



My Answer:
> In order to prevent this issue of multiple actions being executed when multiple requests are made simultaneously, you can use database transactions to ensure data consistency.

Here is an example of how you can modify your code to use transactions:

php
public function useractions(Requests $request){
$entityManager = $this->getDoctrine()->getManager();
$user = $entityManager->getRepository(User::class)->find($userId);

$entityManager->beginTransaction();

try {
// Perform the necessary actions here

// Update the user's token count
$user->setTokens($user->getTokens() - 1);
$entityManager->persist($user);
$entityManager->flush();

// Create the action entity
$action = new Action();
$action->setUser($user);
// Set other action properties
$entityManager->persist($action);
$entityManager->flush();

$entityManager->commit();
} catch (\Exception $e) {
$entityManager->rollback();
throw $e;
}

return new Response('Action performed successfully');
}


By using transactions, you can ensure that the updates to the User and Action entities are atomic and consistent, even when multiple requests are made simultaneously. This will help prevent the issue of multiple actions being executed for a user with limited tokens.

Rate this post

3 of 5 based on 5538 votes

Comments




© 2024 Hayatsk.info - Personal Blogs Platform. All Rights Reserved.
Create blog  |  Privacy Policy  |  Terms & Conditions  |  Contact Us