Roh*_*wad 6 mysql innodb deadlock
我正在 PHP 框架(Codeigniter 2.1.0)中开发 LMS 应用程序。我正在使用 MySQL 数据库。数据库中的所有表都有innodb引擎。我还在每个表上创建了索引。现在我正在本地使用 Jmeter 2.9 版同时对 200 个用户进行负载测试。在负载测试期间,在特定页面操作中,我遇到了Deadlock Found错误。我将原始查询更改为新查询,但再次发生相同的错误。
我已经编写了 save_interactions 函数,它需要四个参数交互数组、module_id、course_id、user_id & 被 AJAX 脚本调用了很多次。如果特定的interaction_id 不存在于该表中,则以下脚本将插入记录,否则更新查询将被触发。
public function save_interactions($interaction_array,$modid,$cid,$uid)
{
foreach($interaction_array as $key=>$interact_value)
{
$select_query = $this->db->query("SELECT COUNT(*) AS total FROM `scorm_interactions` WHERE `mod_id`='".$modid."' AND `course_id`='".$cid."' AND `user_id`='".$uid."' AND `interaction_id`='".$interact_value[0]."'");
$fetchRow = $select_query->row_array();
if($fetchRow['total']==1)
{
$update_data = array(
"interaction_type"=>$interact_value[1],
"time"=>$interact_value[2],
"weighting"=>$interact_value[3],
"correct_response"=>$interact_value[4],
"learner_response"=>$interact_value[5],
"result"=>$interact_value[6],
"latency"=>$interact_value[7],
"objectives"=>$interact_value[8],
"description"=>$interact_value[9]
);
$this->db->where('mod_id', $modid);
$this->db->where('course_id', $cid);
$this->db->where('user_id', $uid);
$this->db->where('interaction_id', $interact_value[0]);
$this->db->update('scorm_interactions', $update_data);
}else
{
$insert_data = array(
"user_id"=>$uid,
"course_id"=>$cid,
"mod_id"=>$modid,
"interaction_id"=>$interact_value[0],
"interaction_type"=>$interact_value[1],
"time"=>$interact_value[2],
"weighting"=>$interact_value[3],
"correct_response"=>$interact_value[4],
"learner_response"=>$interact_value[5],
"result"=>$interact_value[6],
"latency"=>$interact_value[7],
"objectives"=>$interact_value[8],
"description"=>$interact_value[9]
);
$this->db->insert('scorm_interactions', $insert_data);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到了这种类型的错误:
尝试获取锁时发现死锁;尝试重新启动事务
UPDATE `scorm_interactions` SET
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
WHERE
`mod_id` = '4' AND
`course_id` = '5' AND
`user_id` = '185' AND
`interaction_id` = 'Question2_1'
;
Filename: application/models/user/scorm1_2_model.php Line Number: 234
Run Code Online (Sandbox Code Playgroud)
谁能建议我如何避免死锁?
查看 PHP 中的控制流。它对我说:
mod_id, course_id, user_id,interaction_idINSERT新行UPDATE所有其他列为 INSERT 和 UPDATE 场景提供了三 (3) 种机制
REPLACE INTO `scorm_interactions` SET
`mod_id` = '4',
`course_id` = '5',
`user_id` = '185',
`interaction_id` = 'Question2_1',
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
;
Run Code Online (Sandbox Code Playgroud)
或者
REPLACE INTO `scorm_interactions`
(`mod_id`,`course_id`,`user_id`,`interaction_id`,
`interaction_type`,`time`,`weighting`,`correct_response`,
`learner_response`,`result`,`latency`,`objectives`,`description`) VALUES
('4','5','185','Question2_1','choice','10:45:31','1','Knees*',
'Knees*','correct','0000:00:02.11','Question2_1','');
Run Code Online (Sandbox Code Playgroud)
这在mod_id, course_id, user_id,上机械地执行 DELETE 和 INSERTinteraction_id
INSERT INTO `scorm_interactions`
(`mod_id`,`course_id`,`user_id`,`interaction_id`,
`interaction_type`,`time`,`weighting`,`correct_response`,
`learner_response`,`result`,`latency`,`objectives`,`description`) VALUES
('4','5','185','Question2_1',
'choice','10:45:31','1','Knees*',
'Knees*','correct','0000:00:02.11','Question2_1','')
ON DUPLICATE KEY UPDATE
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
;
Run Code Online (Sandbox Code Playgroud)
您是否知道可以对要精确更新的行执行排他锁?
根据MySQL 文档,您可以SELECT在该行上运行查询并在此过程中发出行锁。例如:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
Run Code Online (Sandbox Code Playgroud)
这将锁定整个表并允许更新 counter_field 列。
在您的情况下,只需背靠背运行两个查询
SELECT * FROM `scorm_interactions`
WHERE `mod_id` = '4',
AND `course_id` = '5',
AND `user_id` = '185',
AND `interaction_id` = 'Question2_1'
FOR UPDATE ;
UPDATE `scorm_interactions` SET
`interaction_type` = 'choice',
`time` = '10:45:31',
`weighting` = '1',
`correct_response` = 'Knees*',
`learner_response` = 'Knees*',
`result` = 'correct',
`latency` = '0000:00:02.11',
`objectives` = 'Question2_1',
`description` = ''
WHERE `mod_id` = '4'
AND `course_id` = '5',
AND `user_id` = '185',
AND `interaction_id` = 'Question2_1'
;
Run Code Online (Sandbox Code Playgroud)
作为安全缓冲,如果流量是写密集的,请尝试增加innodb_lock_wait_timeout。请参阅我的 StackOverflow 帖子:如何调试超出锁定等待超时?
试一试 !!!