Объясните необъяснимую тупиковую ситуацию

Прежде всего, я не Я не вижу, как я могу получить любую взаимоблокировку, поскольку я не использую явную блокировку, задействована только одна таблица, есть отдельный процесс для вставки, выбора и обновления строк, только одна строка вставляются или обновляются за раз, и каждый процесс выполняется редко (возможно, раз в минуту).

Это очередь электронной почты:

CREATE TABLE `emails_queue` (
  `id` varchar(40) NOT NULL,
  `email_address` varchar(128) DEFAULT NULL,
  `body` text,
  `status_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status` enum('pending','inprocess','sent','discarded','failed') DEFAULT NULL,
  KEY `status` (`status`),
  KEY `status_time` (`status`,`status_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

Процесс генерации в ответ на какое-либо действие пользователя, но примерно каждые 90 секунд, выполняет вставка в таблицу, устанавливающая статус «ожидает».

Существует процесс мониторинга, который каждую минуту проверяет, не является ли количество «ожидающих» и «неудачных» электронных писем чрезмерным. На его выполнение уходит меньше секунды, и у меня никогда не возникало никаких проблем.

Каждую минуту процесс отправки захватывает все ожидающие письма. Он просматривает одно электронное письмо за раз, устанавливает свой статус на «в процессе», пытается отправить его и, наконец, устанавливает свой статус соответственно на «отправлено», «отклонено» (у него есть причины для решения, что электронное письмо не должно выходить) или «сбой» (отклонено Система SMTP).

Заявление для установки статуса необычно.

UPDATE emails_queue SET status=?, status_time=NOW() WHERE id=? AND status = ?

То есть я обновляю статус только в том случае, если текущий статус уже такой, каким я считаю. До этого механизма я случайно запускал два процесса отправки, и каждый из них пытался отправить одно и то же электронное письмо. Теперь, если бы это произошло, один процесс успешно переместил бы электронное письмо из «ожидающего» в «находящееся в процессе», но второй обновил бы нулевые строки, обнаружил бы проблему и пропустил это электронное письмо.

Проблема в том, примерно один раз из 100 обновление вообще не выполняется! Я получаю com.mysql.jdbc. exceptions.jdbc4.MySQLTransactionRollbackException: обнаружена тупиковая ситуация при попытке получить блокировку; попробуйте перезапустить транзакцию

WTH?

Это единственная таблица и единственный запрос, с которым это происходит, и это происходит только в производственной среде (чтобы максимально затруднить ее исследование).

Единственные две вещи, которые кажутся совершенно необычными (1) обновляют столбец, который участвует в предложении WHERE, и (2) (2) (неиспользуемое) автоматическое обновление status_time.

Я ищу любые предложения или методы диагностики.

13
задан Malvolio 11 May 2011 в 20:28
поделиться