блокировка записей БД для параллелизма между потоками - PullRequest
1 голос
/ 06 февраля 2012

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

Мое приложение отслеживает сеансы сетевых пользователей в системе.Каждый сеанс соответствует одной записи в базе данных.Сеанс может быть закончен одним из двух способов.Либо получено сообщение «Стоп», либо время сеанса может истечь.Первый случай прост, он обрабатывается в потоке обработки сообщений, и все в порядке.В последнем случае возникает проблема.

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

Я мог бы использовать семафор или тому подобное и просто запретить обработку потока сообщений во время тайм-аута, поскольку он должен запускаться только каждые 30секунд или минут.Однако, по мере того, как пользовательская таблица становится большой, это может привести к серьезным проблемам с производительностью.Я думаю, что мне хотелось бы узнать, как в ветке сообщений эта запись в настоящий момент обрабатывается веткой тайм-аута.Если бы я мог добиться этого, я мог бы либо отбросить сообщение, либо дождаться окончания потока времени ожидания, но только в случае конфликтов, а не всегда.

В настоящее время мое приложение использует JDBC напрямую.Был бы более простой / стандартный метод решения этой проблемы, если бы я использовал такую ​​среду, как Hibernate?

1 Ответ

2 голосов
/ 06 февраля 2012

Это отличная возможность для возникновения всевозможных сумасшедших ошибок, а некоторые из них могут вызвать проблемы с производительностью.

Классическим решением было бы использование транзакций (http://dev.mysql.com/doc/refman/5.0/en/commit.html). Это позволяет вам гарантировать согласованность ваших данных - но длительная транзакция в базе данных превращает ее в огромное узкое место; если вы "находите тайм-аут сеансов" "код выполняется в течение минуты, транзакция может выполняться в течение всего этого периода, эффективно блокируя доступ для записи в затронутые таблицы. Большинство систем не справятся с этим.

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

Вы определяете состояния сеанса как «инициированный», «запущенный», «тайм-аут - закрытие», «тайм-аут - закрыто» и «остановлен пользователем» (например).

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

  • обновить все записи, чье время окончания
  • для каждой записи, статус которой «тайм-аут - закрытие»
    • делай все, что тебе нужно
    • обновить эту запись, чтобы установить статус «тайм-аут - закрыто», где статус = «тайм-аут - закрытие»
  • следующая запись

Все остальные попытки изменить текущее состояние записи сеанса должны проверять, является ли текущий статус действительным для предпринятого изменения.

Например, «ручной» код остановки должен выглядеть примерно так:

update sessions
set status = "stopped by user"
where session_id = xxxxx
and status = 'running'

Если подпрограмма автоматического закрытия была запущена во время между отображением пользовательского интерфейса и кода базы данных, предложение where не будет соответствовать ни одной записи, поэтому остальная часть кода просто не запускается.

Чтобы это работало, весь код, который изменяет состояние сеанса, должен проверить его предварительные условия; Наиболее удобный способ - это кодировать статус и разрешенные переходы в отдельную таблицу базы данных.

Вы также можете написать триггеры для обеспечения этой логики, хотя я обычно не фанат триггеров - делайте это только если вам нужно.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...