Добавить колонку "PrintStatus".
- Когда данные добавляются, он установлен (скажем) 1, «Не печатается».
- Когда клиент запрашивает для данных для печати, только возвращать данные, где PrintStatus = 1
- Когда клиент берет данные для печати, установите его (скажем) 2, «Быть Printed»
- Когда клиент заканчивает печать, установить статус на 3, «Печатный»
- Если по какой-либо причине клиент не печатает данные, установите статус обратно в 1 (и PrintedAt обратно в нуль)
Это оставляет дворника вопрос, что произойдет, если печать не удалась, и этот факт не сообщается (потому что дворник вытащил вилку на сервер. Не смейтесь, это произошло здесь, хотя это был технический ремонт парень, который на самом деле должен был знать лучше) Если вы беспокоитесь о таких вещах:.
- Добавить некоторую форму времени регистрации, например, столбец «PrintedAt» , который устанавливается равным null, когда для параметра PrintStatus установлено значение 1, и установите значение getdate(), когда установлено значение PrintStatus 2. Боковое преимущество: теперь вы знаете, когда (или, возможно, «какая печать») были напечатаны ваши данные!
- PrintStatus устанавливается в 3 раза при печати. Таким образом, если PrintStatus = 2, печать имеет (до сих пор) значение getdate() - PrintedAt для запуска.
- Регулярно выполняйте регулярные расписания (рабочие задания SQL-агента). Он проверяет таблицу и обнаруживает ли какие-либо строки с PrintStatus = 2, где столбец PrintedAt больше вашего допуска (1 день? 2 часа?). Любые такие строки «откатываются», устанавливая PrintStatus в 1 и PrintedAt равными null.
Это может показаться излишним, но вы расскажете мне, насколько важны для вас согласованные данные.
Добавлено:
Да, параллелизм и последовательность является проблемой. Хотя вы можете общаться с BEGIN TRANSACTION ... COMMIT/ROLLBACK
, я предпочитаю использовать силу неявных транзакций. Вот один из способов:
Это создает таблицу тестирования с некоторыми данными:
-- Set up test data
CREATE TABLE Test
(
Data int not null identity(1,1)
,PrintStatus tinyint not null
,PrintedAt datetime null
)
INSERT Test (PrintStatus) values
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
SELECT *
from Test
GO
Этот бит содержит оператор UPDATE, который обновляет все строки, которые нужно распечатать, и используется предложение OUTPUT для хранения этих элементов в временная таблица. Содержимое этой таблицы затем возвращается в процедуру печати.
-- First pass: Get everything to pring
DECLARE @ToBePrinted table
(Data int not null)
UPDATE Test
set
PrintStatus = 2
,PrintedAt = getdate()
output inserted.Data into @ToBePrinted (Data)
where PrintStatus = 1
SELECT Data PrintThese
from @ToBePrinted
SELECT * from Test
GO
Здесь мы добавляем еще три строки данных, а затем снова запускаем процедуру. Старые предметы не выбраны, новые.
-- Second pass: Add three new items, they (and only they) get selected
INSERT Test (PrintStatus) values
(1),(1),(1)
SELECT *
from Test
DECLARE @ToBePrinted table
(Data int not null)
UPDATE Test
set
PrintStatus = 2
,PrintedAt = getdate()
output inserted.Data into @ToBePrinted (Data)
where PrintStatus = 1
SELECT Data PrintThese
from @ToBePrinted
SELECT * from Test
Это работает из-за свойств ACID SQL Server - в частности, I). После того, как одно из выражений существа изменяет содержимое таблицы, ни один другой оператор не может получить доступ к изменяемым данным до тех пор, пока выполнение инструкции не будет завершено. (Если вы не настолько глупы, чтобы использовать NOLOCK. Не используйте NOLOCK.)
отметьте его как «in progress», а не только логическое значение. –
Также отметьте его отметкой времени, когда началась операция печати, поэтому никто не будет ждать неделю для выполненного задания на печать, которое умерло. – glenebob