I am facing an issue with a deadlock but I'm failing to understand how both transactions are linked and causing the deadlock.
My log errors are as follows.
Transactiion 1:SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; The SQL being executed was:
UPDATE job_instruction ji\n
INNER JOIN ji_temp2 ON ji.id = ji_temp2.id\n
SET ji.job_instruction_group_id = ji_temp2.job_instruction_group_id"
Transaction 2: SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded;
UPDATE inventory SET
on_hand_quantity = ifnull(on_hand_quantity,0) + (1)\n
,allocated_quantity = ifnull(allocated_quantity,0) + (1)\n
,in_transit_quantity = ifnull(in_transit_quantity,0) + (-1)\n
,suspended_quantity = ifnull(suspended_quantity,0) + (0)\n
,updated_at = 1737630861\n
WHERE id = 2474210
The php code for transaction 1:
\Yii::$app->db->createCommand()->batchInsert(
JobInstructionGroup::tableName(),
['job_id', 'unit_of_measure', 'inventory_id', 'units', 'quantity', 'out_bound_status_flow_id', 'created_at', 'updated_at', 'created_by', 'updated_by'],
$job_instruction_groups
)->execute();
foreach ($processedCombinations as $data) {
if ($data['count'] > 1) {
$job_instruction_groups[] = [
'job_id' => $data['job_id'],
'unit_of_measure' => $data['unit_of_measure'],
'inventory_id' => $data['inventory_id'],
'units' => $data['units'],
'quantity' => $data['quantity'],
'out_bound_status_flow_id' => $data['out_bound_status_flow_id'],
'created_at' => time(),
'updated_at' => time(),
'created_by' => \Yii::$app->user->identity->id,
'updated_by' => \Yii::$app->user->identity->id,
];
$jobIds[] = $data['job_id'];
// $inventoryIds[] = $data['inventory_id'];
// $outBoundStatusFlowIds[] = $data['out_bound_status_flow_id'];
}
}
\Yii::$app->db->createCommand("CREATE TEMPORARY TABLE ji_temp1 AS SELECT * FROM job_instruction WHERE job_instruction.job_id IN (".implode(',',array_unique($jobIds)).")")->execute();
\Yii::$app->db->createCommand("
CREATE TEMPORARY TABLE ji_temp2 AS SELECT ji_temp1.id,
job_instruction_group.id AS job_instruction_group_id
from ji_temp1
INNER JOIN shipment_detail_child
ON shipment_detail_child.job_instruction_id = ji_temp1.id
INNER JOIN shipment_detail
ON shipment_detail.id = shipment_detail_child.shipment_detail_id
INNER JOIN shipment_header
ON shipment_header.id = shipment_detail.shipment_header_id
INNER JOIN job_instruction_group
ON job_instruction_group.job_id = ji_temp1.job_id
AND job_instruction_group.inventory_id = ji_temp1.inventory_id
AND job_instruction_group.out_bound_status_flow_id = shipment_header.out_bound_status_flow_id")->execute();
\Yii::$app->db->createCommand("
UPDATE job_instruction ji
INNER JOIN ji_temp2 ON ji.id = ji_temp2.id
SET ji.job_instruction_group_id = ji_temp2.job_instruction_group_id")->execute();
The php code for transaction 2:
Yii::$app->db->createCommand('UPDATE inventory SET
on_hand_quantity = ifnull(on_hand_quantity,0) + (:on_hand_quantity)
,allocated_quantity = ifnull(allocated_quantity,0) + (:allocated_quantity)
,in_transit_quantity = ifnull(in_transit_quantity,0) + (:in_transit_quantity)
,suspended_quantity = ifnull(suspended_quantity,0) + (:suspended_quantity)
,updated_at = :updated_at
WHERE id = :id',
[ ':id' => $id,
':on_hand_quantity'=>$on_hand_quantity,
':allocated_quantity'=>$allocated_quantity,
':suspended_quantity'=>$suspended_quantity,
':in_transit_quantity'=>$in_transit_quantity,
':updated_at'=>$time])->execute();
My transaction 2 is specific to a where clause and in transaction 1 I have not used any inventory table(Although shipment child and shipment_header does have the relation) so could that be causing a deadlock ? Or another case that I thought is maybe the both transaction aren't related to a specific deadlock but the time is same tho.
A suggestion to optimize the query would also be appreciated if that can resolve the case.