2010-02-25 4 views
4

У меня есть серверное приложение и база данных. Несколько экземпляров сервера могут запускаться одновременно, но все данные поступают из одной базы данных (на некоторых серверах это postgresql, в других случаях ms sql server).блокировка записей базы данных

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

Процесс зависит от одной таблицы (назовем ее «ProcessTable»). То, что я делаю, до того, как какой-либо сервер начнет часовой процесс, я установил в ProcessTable флаг boolean, который указывает, что эта запись «заблокирована» и обрабатывается (не все записи в этой таблице обрабатываются/блокируются, поэтому я необходимо специально отметить каждую запись, которая необходима процессу). Поэтому, когда следующий экземпляр сервера приходит, пока предыдущий экземпляр все еще обрабатывается, он видит логические флаги и выдает исключение.

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

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

Итак, мой вопрос: как мне предотвратить одновременное изменение двух серверов из обоих столбцов LockInProgress в таблице параметров ... или я об этом неправильно?

Обратите внимание, что мне нужно поддерживать сервер postgresql и ms sql, поскольку некоторые серверы используют одну базу данных, а некоторые серверы используют другую.

Заранее спасибо ...

ответ

0

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

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

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

+0

Это лучшая идея, а затем ответ от Прадипа, и если да, то почему? Похоже, что это может сработать, но оно также кажется немного более сложным (и, возможно, менее «кросс-платформой») ... Я мог ошибаться ... – user85116

+0

Возможно, вам придется писать разные sproc для каждой поддерживаемой платформы , но нетрудно написать какой-то плагин mecahnism для поддержки нескольких операций на платформе. Ключевым моментом этого подхода является то, что он использует собственные механизмы блокировки и семантику (т. Е. Один процесс блокируется до тех пор, пока блокировка не станет свободной). – ConcernedOfTunbridgeWells

1

Как насчет того, чтобы сначала зафиксировать запись, а затем обновить запись, чтобы показать «заблокирован». Это позволит избежать второго экземпляра, чтобы получить блокировку успешно, и, таким образом, обновление записи не удалось.

Цель состоит в том, чтобы зафиксировать и обновить как один атомный шаг.

+0

Можете ли вы рассказать об этом немного? Я использую jdbc на интерфейсе ... Является ли java.sql.Connection.TRANSACTION_SERIALIZABLE, что я здесь? – user85116

+0

Я сделал это несколько лет назад в процедуре Oracle PL/SQL. Сначала вы получаете блокировку строки. При успешной блокировке проверьте значение, если оно уже заблокировано, в противном случае обновление «заблокировано» и отпустите блокировку. Это позволит убедиться, что второй поток получит блокировку только после того, как 1-й поток освободит его, и теперь он будет «заблокирован». – Pradeep

+0

Цитирование: «Одним из примеров уровня изоляции транзакции является TRANSACTION_READ_COMMITTED, который не позволит доступ к значению до тех пор, пока оно не будет выполнено. Другими словами, если для уровня изоляции транзакции установлено значение TRANSACTION_READ_COMMITTED, СУБД не разрешить грязные чтения. Интерфейс Connection включает пять значений, которые представляют уровни изоляции транзакций, которые вы можете использовать в JDBC ». по ссылке: http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Statement.html – Pradeep

0

Я думал об этом, и я думаю, что это самый простой способ делать вещи; Я просто выполнить команду:

update settings set settingsValue = '333' where settingsKey = 'ProcessLock' and settingsValue = '0' 

«333» будет уникальное значение, которое получает каждый серверный процесс (на основе даты/времени, имя сервера, + случайное значение и т.д.).

Если никакой другой процесс не заблокировал таблицу, то значение settingsValue будет равно = 0, и этот оператор будет корректировать settingsValue.

Если другой процесс уже заблокировал таблицу, то это утверждение становится не-оператором, и ничего не изменяется.

Затем я немедленно совершаю транзакцию.

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

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