Тестирование связанного сервера внутри триггера или процедуры

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

CREATE TRIGGER myTtableUpdate ON myTable
AFTER UPDATE AS
IF (COLUMNS_UPDATED() > 0)
BEGIN
DECLARE @retval int;
BEGIN TRY
EXEC @retval = sys.sp_testlinkedserver N'my_linked_server';
END TRY
BEGIN CATCH
SET @retval = sign(@@error);
END CATCH;

IF (@retval = 0)
BEGIN
UPDATE remoteTable SET remoteTable.datafield = i.datafield
FROM my_linked_server.remote_database.dbo.myTable remoteTable
INNER JOIN inserted i ON (remoteTable.id = i.id)
END
END -- end of trigger

К сожалению, когда соединение не работает, я получаю сообщение об ошибке
'Сообщение 3616, уровень 16, состояние 1, строка 2'
'Транзакция обречена на триггер. Пакетная обработка была прервана'
, и выполнен откат локального обновления.

Есть ли способ устранить эту ошибку и сохранить локальные обновления?
Обратите внимание, что я использую SQL Server 2005 Express Edition на обоих компьютерах под управлением Windows XP Pro.

edit1: сервер SQL Express Edition
edit2: оба ПК работают под управлением Windows XP Pro, поэтому это не серверы


person Ragnar    schedule 29.05.2009    source источник
comment
посмотри мой последний комментарий...   -  person KM.    schedule 29.05.2009


Ответы (2)


не пишите на удаленный сервер в триггере.

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

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

declare @OutputTable table (RowID int not null)

insert into my_linked_server.remote_database.dbo.myTable remoteTable(...columns...)
    OUTPUT INSERTED.RowID
    INTO @OutputTable
    SELECT ...columns...
        from NewLocalTable

delete NewLocalTable
   from NewLocalTable           n
       inner join @OutputTable  o ON n.RowID=o.RowID

Комментарий OP на основе EDIT
после вставки в эту новую локальную таблицу запустите задание из триггера (sp_start_job), оно будет выполняться в своей области. Если вы не можете использовать задания сервера sql, используйте xp_cmdshell для выполнения хранимой процедуры (ищите SQLCMD, ISQL или OSQL, я не уверен, что у вас есть). по-прежнему планировать задание каждые N минут, поэтому оно в конечном итоге будет запускаться при установлении соединения.

person KM.    schedule 29.05.2009
comment
Это может почти сработать, за исключением задержки запланированной работы. Кроме того, в Express Edition мне пришлось бы использовать планировщик Windows, который делает задержку очень долгой. - person Ragnar; 29.05.2009
comment
С помощью планировщика вы можете запускать что-то каждые X минут — если этого недостаточно, вам придется пересмотреть свой дизайн и архитектуру. - person DJ.; 29.05.2009
comment
Поскольку ожидаемый результат заключался в том, что обновление будет загружено сразу или, в случае сетевой ошибки, никогда, мне, вероятно, придется запускать планировщик каждую минуту, что не кажется очень привлекательным решением. - person Ragnar; 29.05.2009
comment
запланировать, если каждые 15 минут, но запускать его по запросу от триггера. если версия из триггера не работает, повторная попытка займет в худшем случае 15 минут. Если появится еще одна вставка, ее опробуют раньше. вам просто нужно запустить версию по запросу, используя sp_start_job или xp_cmdshell, поэтому в случае сбоя вы не откатываете все назад. Если это действительно не удается изначально, запланированное задание будет пытаться каждые N минут, вы не можете запрашивать больше, чем это. - person KM.; 29.05.2009

По крайней мере, один из серверов версии Workgroup или выше? Вы можете использовать Service Broker для отправки своих записей вместо связанных серверов, но он не будет работать между выпусками Express из-за лицензионных ограничений. Это решение, основанное исключительно на SQL, предлагает надежность в случае инцидентов (один из серверов недоступен) и ваши обновления будут распространяться в режиме реального времени (как только они будут зафиксированы). На моем сайте есть много примеров того, как это сделать, вы можете начать с этой статьи здесь, на как добиться высокой пропускной способности сообщений.

person Remus Rusanu    schedule 29.05.2009
comment
Я мог бы написать обходной путь в любом месте приложения Java, которое использует эту таблицу sql, но это похоже только на одного клиента, поэтому я надеялся, что смогу изолировать все это в триггере sql и забыть об этом. Спасибо за статью о сервис-брокере. - person Ragnar; 29.05.2009