DISCLAIMER : Not a Codeigniter Person, Just a MySQL DBA
Looking at the flow of control in the PHP. It says to me:
- Check the following
mod_id
,course_id
,user_id
,interaction_id
- If not found,
INSERT
the new row
- If found,
UPDATE
all the other columns
There are three(3) mechanisms provided for INSERT and UPDATE scenarios
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` = ''
;
or
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','');
This mechanically performs DELETE and INSERT on mod_id
, course_id
, user_id
, interaction_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` = ''
;
Did you know you can perform an exclusive lock on rows you intend to update with precision?
According the MySQL Documentation, you can run a SELECT
query on the very row and issue a row lock along the way. For example:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
This will lock the entire table and allow an UPDATE of the counter_field column.
In your case, simply run the two queries back-to-back
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'
;
EPILOGUE
As a safety cushion, try increasing innodb_lock_wait_timeout if the traffic is write-heavy. See my StackOverflow post : How to debug Lock wait timeout exceeded?
Give it a Try !!!
Best Answer
The simplest way to reduce deadlocks - proper indexing. Make sure, that client's read requests not involving table/clustered index scans - if any - this is the open gates to deadlocks
And make sure, that your index has its
allow_page_lock
andallow_row_lock
options ON