I have a code section like this:
public function storeOrUpdate(Request $request)
{
if(Order::where('order_id','=',$request->order_id)->exists()){
// lof of complicate stuff (Case A)
// many queries etc.
return;
}
Order::create(['order_id' => $request->order_id]);
// other complicated stuff (Case B)
}
There are two things that are currently failing here:
- Case B should only be executed once, namly for the first request of an order_id. For each following request for that order_id, case A should be executed.
- Case A shall only happen after all queries in case B are executed.
This code is not using transactions or locks, so it may cause a race-condition, that two current requests may both execute case B. Also its possible that two requests come in and one executes Case B
and the other Case A
while Case B
is not fully completed.
My idea to fix it, is as follows. First, create a unique constrain on the order_id
column of the orders table.
Then, change the function like this:
public function storeOrUpdate(Request $request)
{
DB::beginTransaction();
try{
Order::create(['order_id' => $request->order_id]);
// Do complicated stuff (Case B)
DB::commit();
}catch(DBException $ex) {
if ($e->errorInfo[1] == 1062) {
//Duplicate key
DB::rollBack();
DB::transaction(function () {
// Do update and
// a lof of complicate stuff (Case A)
// many queries etc.
});
}
}
My idea behind it, is, that two current requests will now both try to create an order and do case B. However, one of them will fail, due to unique key constrains. But a transaction can only fail, if the other transaction is already completed. Thus I can assure that if one transaction fails, case B must have been fully executed and I can now execute A.
Is this reasoning correct?
Does this really assure that the code in case A is only executed when the code in case B is fully executed?
via Chebli Mohamed
Aucun commentaire:
Enregistrer un commentaire