Как лучше всего избегать множественных вставок? - PullRequest
0 голосов
/ 19 марта 2009

У меня есть приложение-служба, которое отслеживает изменения каталога.

Приложение службы будет внимательно следить за каталогом. Вот как это работает:

  1. Сон X минут
  2. Сканирование по каталогу, посмотреть, есть ли новые дополнения
  3. Запуск одной нити за одно добавление
  4. Повтор 1-3

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

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

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

Я думаю об использовании оператора блокировки, который блокирует транзакцию базы данных. Это лучший подход?

P / S: я пишу .Net сервис, который общается с базой данных MySQL.

Ответы [ 6 ]

1 голос
/ 19 марта 2009

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

[ПРАВИТЬ] Вы боитесь скачка напряжения. Куда? На сервере или клиенте? Вот ваши варианты:

  1. Сбой сервера. Просто попросите клиентов проверить код ошибки «соединение потеряно» и повторите попытку вставки, пока это не удастся. Чтобы выяснить этот код ошибки, либо выключите сервер в середине вставки, либо вытяните сетевой кабель вашего клиента (или оба; иногда вы получаете разные ошибки при непредвиденных проблемах в сети).

  2. Сбой клиента (гораздо более вероятно, поскольку клиенты, как правило, являются дешевыми ПК. Если у пользователей есть доступ к нему, он в конечном итоге будет заражен вирусом, или файловая система будет повреждена, у нее не хватит памяти, кто-то установит что-нибудь «классное», которое уничтожит жизненно важную DLL или еще много чего). В этом случае вам необходимо снова запустить клиент, проверить, что уже было вставлено (с помощью ключа приложения), и продолжить с него.

Ключ приложения - это идентификатор строки, связанной с вашим бизнес-процессом. Например, если вы продаете карты, ключом приложения может быть название автомобиля, имя клиента и отметка времени.

1 голос
/ 19 марта 2009

Я бы сначала посмотрел на то, почему вы хотите это сделать. Обычно приложения работают так, нет проблем в 2 клиентах, делающих вставки одновременно (ну, кроме неправильных подходов в коде).

Также решение будет зависеть от сценария. Одним из вариантов является наличие очереди сообщений Microsoft (MSMQ) и перемещение вставок из этих служб, поэтому загрузка вставок контролируется процессом, который читает из очереди.

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

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

Муравей другой:

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

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

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

Для встроенной поддержки у вас может быть случай для распределенной транзакции, которая также включает в себя файловую систему (ms смотрел на проблему файловой системы, но я не помню, делали ли они когда-нибудь что-нибудь на более новой ОС) , Распределенные транзакции, однако, довольно сложно настроить (msdtc и доступ к используемым портам).

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

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

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

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

0 голосов
/ 20 марта 2009

Я думаю, что лучший вариант здесь - следовать предложению Аарона и отчитываться о потоках после обработки каждого файла; затем обновите базу данных из однопоточного класса 'manager'.

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

Однако в одном из ваших комментариев говорится, что запущено несколько служб. Это правда? Несколько служб Windows наблюдают за одним и тем же каталогом И выполняют многопоточную обработку? Зачем? Я думаю, вам придется лучше защищать эту архитектуру, чтобы получить лучшие ответы.

0 голосов
/ 20 марта 2009

Как многие говорили раньше: это плохо. Это искусственно создаст узкое место.

Но если вы действительно хотите это сделать, вот ваши варианты:

а) создать первичный ключ на столе. Вы должны сделать это в любом случае для чистого дизайна БД. Чтобы проверить действительность PK, база данных должна использовать блокировку, которая заставит ваши вставки в последовательность.

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

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

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

0 голосов
/ 19 марта 2009

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

[EDIT]

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

Затем эти потоки сообщают основному потоку, который собирает результаты и вставляет их в цикл.

0 голосов
/ 19 марта 2009

Если у вас установлено несколько служб Windows, просматривающих одну и ту же папку, или если у вас есть многопоточная служба Windows, вы получите несколько одновременных вставок. В противном случае вам не нужно беспокоиться.

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