2009-02-18 4 views
3

У меня есть таблица, которую я использую в качестве рабочей очереди. По существу, он состоит из первичного ключа, части данных и флага состояния (обрабатывается/не обрабатывается). У меня есть несколько процессов, пытающихся захватить следующую необработанную строку, поэтому я должен убедиться, что они соблюдают правильную семантику блокировки и обновления, чтобы избежать гадости. С этой целью я определил хранимую процедуру они могут позвонить:SQL Server SELECT/UPDATE Сохраненная процедура Weirdness

CREATE PROCEDURE get_from_q 
AS 
DECLARE @queueid INT; 
BEGIN TRANSACTION TRAN1; 

SELECT TOP 1 
    @queueid = id 
FROM 
    MSG_Q WITH (updlock, readpast) 
WHERE 
    MSG_Q.status=0; 

SELECT TOP 1 * 
FROM 
    MSG_Q 
WHERE 
    [email protected]; 

UPDATE MSG_Q 
SET status=1 
WHERE [email protected]; 

COMMIT TRANSACTION TRAN1; 

Обратите внимание на использование «С (UPDLOCK, READPAST)», чтобы убедиться, что я заблокировать целевую строку и игнорировать строки, которые так же запертые уже.

Теперь эта процедура работает, как указано выше, и это здорово. Однако, хотя я собирал это вместе, я обнаружил, что если второй SELECT и UPDATE меняются по порядку (т. Е. Сначала UPDATE, затем SELECT), я вообще не получил данных. И нет, неважно, был ли второй SELECT до или после окончательного COMMIT.

Таким образом, мой вопрос заключается в том, почему порядок второго SELECT и UPDATE имеет значение. Я подозреваю, что есть что-то тонкое, что я не понимаю, и я волнуюсь, что это укусит меня позже.

Любые подсказки?

ответ

1

Хотя не отвечая прямо на ваш вопрос здесь, вместо того, чтобы изобретать колесо и делать жизнь трудной для себя, если вы не наслаждаетесь ею, конечно ;-), могу ли я предложить вам использовать SQL Server Service Broker.

Это обеспечивает существующую базу для использования очередей и т.д.

Чтобы узнать больше визита.

Service Broker Link

Теперь вернусь к вопросу, я не в состоянии воспроизвести вашу проблему, как вы увидите, если выполнить следующий код, данные возвращаются независимо от того, Os ЗЕЬЕСТА/обновления.

Итак, ваш пример выше.

create table #MSG_Q 
(id int identity(1,1) primary key,status int) 
insert into #MSG_Q select 0 

DECLARE @queueid INT 
BEGIN TRANSACTION TRAN1 
SELECT TOP 1 @queueid = id FROM #MSG_Q WITH (updlock, readpast) WHERE #MSG_Q.status=0 
UPDATE #MSG_Q SET status=1 WHERE [email protected] 
SELECT TOP 1 * FROM #MSG_Q WHERE #[email protected] 
COMMIT TRANSACTION TRAN1 

select * from #MSG_Q 
drop table #MSG_Q 

Возвращает результаты (1,1) и (1,1)

Теперь поменяв порядок отчетности.

create table #MSG_Q 
(id int identity(1,1) primary key,status int)  
insert into #MSG_Q select 0 

DECLARE @queueid INT 
BEGIN TRANSACTION TRAN1 
SELECT TOP 1 @queueid = id FROM #MSG_Q WITH (updlock, readpast) WHERE #MSG_Q.status=0 
SELECT TOP 1 * FROM #MSG_Q WHERE #[email protected] 
UPDATE #MSG_Q SET status=1 WHERE [email protected] 
COMMIT TRANSACTION TRAN1 

select * from #MSG_Q 
drop table #MSG_Q 

Результаты: (1,0), (1,1), как ожидалось.

Возможно, возможно, вам удастся решить вашу проблему дальше?

+0

Хм, ссылка кажется сломана, но это работает: http://msdn.microsoft.com/en-us/library/ms345108.aspx Кроме того, я застрял только с подключением ODBC к SQL-серверу db, поэтому я не уверен, что Service Broker будет работать на меня. Выглядит * отлично * хотя .... – 2009-02-18 19:44:18

2

транзакциями по умолчанию для чтения COMMITTED:

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

http://msdn.microsoft.com/en-us/library/aa259216.aspx

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

1

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

С тех пор я схватил бесплатный MS SQL Server Management Studio Express и все работает отлично. Для тех, кто заинтересован, то URL в ГОСО здесь:

MS SQL Server SMSE

Не забудьте установить пакет обновления MSXML6, тоже:

MSXML Service Pack 1

Таким образом, полностью мое плохое в этом случае , :-(

Главное спасибо и вам, ребята, за ваши ответы. Вы помогли мне подтвердить, что то, что я делаю, должно работать, что привело меня к изменению, которое я должен был сделать, чтобы «решить» проблему. никогда не было так много!

0

Еще одна точка - в том числе «УСТАНОВИТЬ НАЗВАНИЕ ВКЛ» в хранимой процедуре фиксированные вещи для всех клиентов ODBC. По-видимому, количество строк для первого выбора путало клиентов ODBC и не позволяло SQL Server вернуть это значение делает вещи работают отлично ...

Смежные вопросы