Два потока, читающие из одной и той же таблицы: как заставить оба потока не читать один и тот же набор данных из таблицы ЗАДАЧ - PullRequest
2 голосов
/ 15 ноября 2011

У меня есть поток задач, работающий в двух отдельных экземплярах tomcat.Потоки задач одновременно считывают (используя select) таблицу TASKS при определенных условиях, а затем выполняют некоторую обработку.

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

Ответы [ 6 ]

0 голосов
/ 03 апреля 2012

Может ли база данных обеспечить изящное управление этим, во многом будет зависеть от того, использует ли она методы строгой двухфазной блокировки (S2PL) или многоуровневого управления параллелизмом (MVCC) для управления параллелизмом. В MVCC чтения не блокируют записи, и наоборот, поэтому очень легко управлять этим с помощью относительно простой логики. В рамках S2PL вы тратите слишком много времени на блокировку базы данных, чтобы быть хорошим механизмом для управления этим, поэтому вам, вероятно, захочется взглянуть на внешние механизмы. Конечно, внешний механизм может работать независимо от базы данных, просто он не необходим с MVCC.

Базы данных, использующие MVCC: PostgreSQL, Oracle, MS SQL Server (в определенных конфигурациях), InnoDB (кроме уровня изоляции SERIALIZABLE) и, возможно, многие другие. (Это те, которые я знаю по от руки.)

Я не нашел никаких подсказок в вопросе о том, какой продукт баз данных вы используете, но если это PostgreSQL, вы можете рассмотреть вопрос об использовании рекомендательных блокировок. http://www.postgresql.org/docs/current/interactive/explicit-locking.html#ADVISORY-LOCKS Я подозреваю, что многие другие продукты имеют похожий механизм.

0 голосов
/ 15 ноября 2011

В вашем случае есть лучший инструмент для работы - и это обмен сообщениями. Вы сохраняете элементы, над которыми нужно поработать, и затем пытаетесь синхронизировать доступ между работниками. Существует ряд проблем, которые вам необходимо решить при выполнении этой работы - в общем случае обновление таблицы и выбор из нее не следует смешивать (она блокируется), поэтому сохранение состояния там не работает; и синхронизация в вашем Java-коде невозможна, так как это не выдержит перезапуска сервера.

Используя JMS API с брокером сообщений, таким как ActiveMQ, вы опубликуете сообщение в очереди. Это сообщение будет содержать детали задачи, которая будет выполнена. Посредник сообщений сохранит это где-нибудь (либо в своем собственном хранилище сообщений, либо в базе данных). Рабочие потоки будут тогда подписываться на очередь в посреднике сообщений, и каждое сообщение будет передаваться только одному из них. Это довольно мощная модель, поскольку вы можете иметь сотни потребителей сообщений, которые все выполняют свои задачи, поэтому она хорошо масштабируется. Вы также можете сделать это настолько гибким, насколько это необходимо, чтобы задачи могли выдержать как перезапуск Tomcat, так и брокера.

0 голосов
/ 15 ноября 2011

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

Изменить: Я не видел "не читать"

В этом случае вам нужна другая таблица TaskExecutor (taskId, executorId), и когда какой-то поток запускает задачу, вы помещаете данные в TaskExecutor;и когда вы запускаете другой поток, он просто проверяет, что задача уже выполняется или нет (выберите ... из RanTask, где taskId = ...).Вам также необходимо позаботиться об уровне изоляции для транзакций.

0 голосов
/ 15 ноября 2011

Я думаю, вам нужно увидеть некоторую информацию о том, как работает любой планировщик заданий предприятия, например, с Quartz

0 голосов
/ 15 ноября 2011

Если упомянутое вами TASKS table является таблицей базы данных, я бы использовал изоляцию транзакции.

В качестве предложения, в транзакции, установите атрибут TASK table на какое-то уникальное идентифицируемое значение, если оно не установлено.Совершить тракцию.Если все в порядке, то задача была выбрана потоком.

Я не сталкивался с этим сценарием, поэтому отнеситесь к моему предложению с осторожностью.

0 голосов
/ 15 ноября 2011

Это просто потому, что ваш код (который обращается к базе данных) не выполняет функцию DAO. Сделайте ее синхронизированной, я думаю, что ваша проблема будет решена.

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