gifts2017

Триггер для сохранения таблицы Config перед динамическим обновлением.

Опубликовал Андрей Кондратенко (Kondratenko.as) в раздел Администрирование - Системное

Вначале хотел выложить триггер в своей предыдущей статье http://infostart.ru/public/324751/, но потом понял, что просто выложить не получится, необходимо еще и объяснить, а поскольку материала оказалось слишком много, то пришлось выносить в отдельную статью, и так максимально обрезанную, оставил только самое необходимое.

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

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

Так как у меня MS SQL, то логика была такая:

1)      Создаем табличку [master].[dbo].[sp_backup_config_tables] полную копию Config.

2)      Ставим триггер на таблицу [Config] который при первом выполнении сохраняет таблицу в [sp_backup_config_tables] , а также добавляет еще одну запись в нее (признак того, что идет обновление) , а все последующие транзакции к таблице проверяются на этот признак и, если он есть, то ничего не делают, и на последней транзакции мы удаляем этот признак из таблицы.

Довольно простой алгоритм. Единственная сложность в котором была, это определить окончание обновления, то есть момент, когда этот признак удалить из таблички. Для этого пришлось понять, что происходит в момент обновления конфигурации. Написал три простеньких триггера, соответственно на: добавление, удаление и обновление. Которые писали бы информацию о своем действии в таблицу [Master].[dbo].[Config_Insert] :

 

Создание таблицы:


SET ANSI_NULLS ON
GO
 
SET QUOTED_IDENTIFIER ON
GO
 
CREATE TABLE [dbo].[Config_Insert](
      [FileName] [nvarchar](128) NULL,
      [NomerZapis] [int] NULL,
      [TipOper] [nvarchar](128) NULL
) ON [PRIMARY]


Триггеры: 


GO
USE [ТестоваяБаза]
IF OBJECT_ID ('TEST_Trigger_1C_Config_insert', 'TR') IS NOT NULL
   DROP TRIGGER TEST_Trigger_1C_Config_insert;
GO
CREATE TRIGGER TEST_Trigger_1C_Config_insert
ON [ТестоваяБаза].[dbo].[Config]
for insert
AS
SET NOCOUNT on
insert into [Master].[dbo].[Config_Insert] (FileName,NomerZapis,TipOper) values ((select filename from inserted),(select  COUNT (*) from [Master].[dbo].[Config_Insert])+1,'insert');
 
-----------------------------------------------------------------------------------
GO
USE [ТестоваяБаза]
IF OBJECT_ID ('TEST_Trigger_1C_Config_delete', 'TR') IS NOT NULL
   DROP TRIGGER TEST_Trigger_1C_Config_delete;
GO
CREATE TRIGGER TEST_Trigger_1C_Config_delete
ON [[ТестоваяБаза].[dbo].[Config]
for delete
AS
SET NOCOUNT on
insert into [Master].[dbo].[Config_Insert] (FileName,NomerZapis,TipOper) values ((select filename from deleted),(select  COUNT (*) from [Master].[dbo].[Config_Insert])+1,'delete');
-----------------------------------------------------------------------------------
GO
USE [ТестоваяБаза]
IF OBJECT_ID ('TEST_Trigger_1C_Config_update', 'TR') IS NOT NULL
   DROP TRIGGER TEST_Trigger_1C_Config_update;
GO
CREATE TRIGGER TEST_Trigger_1C_Config_update
ON [ТестоваяБаза].[dbo].[Config]
for update
AS
SET NOCOUNT on 
insert into [Master].[dbo].[Config_Insert] (FileName,NomerZapis,TipOper) values ((select filename from inserted),(select  COUNT (*) from [Master].[dbo].[Config_Insert])+1,'update');

Получилось много статистической информации, к примеру: 

 

 

После анализа нескольких таких таблиц выяснил, что достаточно одного триггера на добавление.

 


GO
USE [ТестоваяБаза]
IF OBJECT_ID ('TEST_Trigger_1C_Config_insert', 'TR') IS NOT NULL
   DROP TRIGGER TEST_Trigger_1C_Config_insert;
GO
CREATE TRIGGER TEST_Trigger_1C_Config_insert
ON [ТестоваяБаза].[dbo].[Config]
for insert
AS
SET NOCOUNT on
 
insert into [Master].[dbo].[Config_Insert] (FileName,NomerZapis,TipOper) values ((select filename from inserted),(select  COUNT (*) from [Master].[dbo].[Config_Insert])+1,'insert');

Так как даже на данном примере видно, что 1С сперва производит добавление новых записей в таблицу, а уже потом их обрабатывает. 

 

В ходе анализа статистической информации из таблицы [Master].[dbo].[Config_Insert] выяснилось, что само обновление представляет из себя просто последовательную запись в таблицу строк содержащих файлы метаданных и файлы описаний конфигурации (обезательные “root”,”version”,”versions”) , а также, что существует несколько вариантов обновления (если судить по изменениям в таблице Config) :

1)      Обычное штатное обновление

2)      «Первое» динамическое обновление (всякое динамическое обновление считается «первым» если оно выполнено первый раз после шатного, так как в таблице Config появляется файл “DynamicallyUpdated” – в котором хранится идентификатор динамического обновления и добавляются файлы измененных метаданных в результате этого динамического обновления в виде “c03b12af-b17c-4e98-b06f-c09e5b8f9fa1_dynupdate_d94ab89a-8c1f-4c62-bec3-c8af26df7864” , где слева от “_dynupdate_” идентификаторо метаданного, а справа идентификатор динамического обновления).

3)      Последующие динамические обновления (все динамические обновления после «первого»)

4)      Штатное обновление после динамического (при шатном обновлении происходит реструктуризация таблицы Config и стирается вся информация о динамическом обновлении, удаляются все записи с “_dynupdate_” и запись “DynamicallyUpdated”)

5)      Отказ от внесения изменений (при любом из вышеперечисленных изменений, конфигуратор попросит вас подтвердить внесения изменения, но при этом в таблицу Config уже будут добавлены записи об изменениях с дополнением “_new” к имени файла и, если вы откажитесь, то они просто будут удалены.)

 

Я смог выделить только эти варианты (возможно есть еще что-то, что я не увидел).

Именно 5-ый пункт стал решающим при выборе типа триггера, так как мы должны закончить все наши «манипуляции» до момента «принятия решения» (подтверждения обновления в конфигураторе). По этому тип триггера “insert” .

Далее оставалось только учесть в алгоритме триггера все 4 варианта обновления.

Во всех 4 случаях будет запись с именем “ root” – так что её можно использовать как признак окончания операции. И, исключив из проверки частные случаи первых 4-х пунктов в виде записей 'dbStruFinal', 'dynamicCommit', 'DynamicallyUpdated', 'root', 'version', 'version', получаем рабочий триггер:

Сам триггер:

 

GO
USE [РабочаяБаза]
--Проверяем есть ли тригер,если есть, то удаляем
IF OBJECT_ID ('KAS_TEST_Trigger_1C_Config', 'TR') IS NOT NULL
   DROP TRIGGER KAS_TEST_Trigger_1C_Config;
GO
--Добавляем триггер
CREATE TRIGGER KAS_TEST_Trigger_1C_Config
ON [РабочаяБаза].[dbo].[Config]
for insert
AS
SET NOCOUNT on
--Объявляем переменные
declare @Int_1C_Vrem_Priznak int
declare @Int_1C_commit int
 
--Необходимо определить первую и последнюю транзакцию.
--Если в таблици нет записи FileName like '%Vrem_Priznak%'
--Значит транзакция первая.
--Так как существеует два типа обновления Обычное и Динамическое то и их признаки разные,
--но все записи идут после 'commit',так что его можно использовать как признак последней итерации
--исключив дальнейшие варианты с 'dbStruFinal','dynamicCommit','DynamicallyUpdated','root','version','versions'
 
select @Int_1C_Vrem_Priznak = COUNT (*) from [master].[dbo].[sp_backup_config_tables] where FileName like '%Vrem_Priznak%'
select @Int_1C_commit= COUNT (*)from inserted where filename like 'dbStruFinal' or filename like 'dynamicCommit' or filename like 'DynamicallyUpdated' or filename like 'root' or filename like 'version' or filename like 'versions' 

if @Int_1C_Vrem_Priznak = 0 and @Int_1C_commit=0
BEGIN
truncate table [master].[dbo].[sp_backup_config_tables];
insert into [master].[dbo].[sp_backup_config_tables] select * from [РабочаяБаза].[dbo].[Config];
delete  [master].[dbo].[sp_backup_config_tables] where FileName in (select filename from inserted)
insert into [master].[dbo].[sp_backup_config_tables] (filename,Creation,Modified,Attributes,DataSize,BinaryData) values ('Vrem_Priznak','01.01.01','01.01.01',0,1,'0x01')
-- для 8.3
--insert into [master].[dbo].[sp_backup_config_tables] (filename,Creation,Modified,Attributes,DataSize,BinaryData,PartNo) values ('Vrem_Priznak','01.01.01','01.01.01',0,1,'0x01',0)
end
 
select @Int_1C_commit= COUNT (*) from inserted where filename like 'commit'

if @Int_1C_commit<> 0 
BEGIN
delete [master].[dbo].[sp_backup_config_tables] where filename like '%Vrem_Priznak%' 
end
 

Данный триггер проверен на платформах 8.2.19.83 и 8.3.5.1231 . И исправно служит для конфигруций «Комплексная автоматизация», «Зарплата и Управление персоналом», «Бухгалтерияя предприятия 2.0» и «Бухгалтерия предприятия 3.0». 

Если надумаете использовать его, то перед выполнением  

insert into [РабочаяБаза].[dbo].[Config] select * from [master].[dbo].[sp_backup_config_tables]

Отключите триггер.

P.s. Если у кого-то возникнут ошибки при работе триггера или какие-либо дополнения, то не стесняемся, оставляем комменты или, если стесняемся, пишем в личку:).

См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. Екатерина Тутубалина (kalaratra) 04.02.15 10:54
2. Алексей Роза (DoctorRoza) 05.02.15 08:32
Да! С этим еще нужно переспать и познать дао "триггера"! :)
3. Руслан Ибрагимов (break) 05.02.15 09:05
до полноты не хватает кода отключения триггера типа DISABLE TRIGGER KAS_TEST_Trigger_1C_Config ON [РабочаяБаза].[dbo].[Config] перед восстановлением config
4. Андрей Кондратенко (Kondratenko.as) 05.02.15 09:13
(3) break, Ну там в конце написано, что перед загрузкой, триггер необходимо отключить. Статья и так получилась большей , я подумал, что тот кто захочет использовать триггер найдет способ его отключить:)
5. Денис Козлов (Akbis) 05.02.15 11:47
select @Int_1C_Vrem_Priznak = COUNT (*) from [master].[dbo].[Config] where FileName like '%Vrem_Priznak%'

и

truncate table [master].[dbo].[Config];

Разве здесь вместо [Config] не должно быть [sp_backup_config_tables] ?
6. Андрей Кондратенко (Kondratenko.as) 05.02.15 11:50
(5) Akbis, Да, вы правы, опечатался , сейчас обновлю
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа