gifts2017

Этюд: Ручное восстановление таблицы из бэкапа

Опубликовал Осипов Сергей (fixin) в раздел Администрирование - Тестирование и исправление

У меня случилась неприятность – в личной базе данных полетела колонка с текстом в таблице, где хранились сообщения, накопленные в почтовой переписке за 5 лет. После запуска CHDBFL текст сообщений исчез во всей таблице, в каждой ее записи!

Всё остальное не пострадало. Я решил не восстанавливать базу из архива (с потерей последних нескольких дней), а ручками перенести тексты из бэкапа. Об этом этюд. Он будет полезен в плане демонстрации ручных навыков работы с XML.

Структура данных

Сообщения хранились в документе пимСообщение. В нем было всего две колонки для текста сообщения:

  • В колонке text хранился обычный текст сообщения
  • В колонке texth хранился текст сообщения в виде HTML, RTF и в других вариантах, в общем случае в виде Структуры, упакованной в ХранилищеЗначения.

Соответственно, нужно было восстановить только два этих поля.

Сообщений было 500 000. Стандартная ВыгрузкаЗагрузкаДанныхЧерезXML от 1С не справилась, написала – не хватает памяти.

Перенести нужно было быстро. Поэтому решил писать свой код, а не муторно искать готовое решение.

Код работает быстро, т.к. не загромождает память. Просто выполняет выгрузку, чтение и запись.

Код выполняю непосредственно в консоли кода.

Выгрузка в XML

Код по выгрузке выглядит так:

З = Новый Запрос("ВЫБРАТЬ Ссылка, ШаблонСообщения ИЗ Документ.пимСообщение");
Выборка = З.Выполнить().Выбрать();
ИмяФайла = "R:\1.xml";

ЗаписьXML = Новый ЗаписьXML();
ЗаписьXML.ОткрытьФайл(ИмяФайла, "windows-1251");
ЗаписьXML.ЗаписатьОбъявлениеXML();
ЗаписьXML.ЗаписатьНачалоЭлемента("items");

Сч = 0;
Пока Выборка.Следующий() Цикл
    Сч = Сч + 1;
    Если Сч % 100 = 0 Тогда
        Состояние("" + Сч + " из " + Выборка.Количество());
    КонецЕсли;
 
    ЗаписьXML.ЗаписатьНачалоЭлемента("item");

    ЗаписьXML.ЗаписатьНачалоЭлемента("link");
    ЗаписьXML.ЗаписатьТекст(ЗначениеВСтрокуВнутр(Выборка.Ссылка));
    ЗаписьXML.ЗаписатьКонецЭлемента();

    Попытка
        Значение = Выборка.Ссылка.Текст;
        ЗаписьXML.ЗаписатьНачалоЭлемента("text");
        ЗаписьXML.ЗаписатьТекст(Значение);
        ЗаписьXML.ЗаписатьКонецЭлемента();
    Исключение
    КонецПопытки;

    Попытка
        Значение = ЗначениеВСтрокуВнутр(Выборка.Ссылка.ТекстХран);
        ЗаписьXML.ЗаписатьНачалоЭлемента("texth");
        ЗаписьXML.ЗаписатьТекст(Значение);
        ЗаписьXML.ЗаписатьКонецЭлемента();
    Исключение
    КонецПопытки;

    ЗаписьXML.ЗаписатьКонецЭлемента();

КонецЦикла;

ЗаписьXML.ЗаписатьКонецЭлемента();

ЗаписьXML.Закрыть();

Загрузка из XML

Код по загрузке выглядит так:

ЧтениеXML = Новый ЧтениеXML();
ИмяФайла = "R:\1.xml";
ЧтениеXML.ОткрытьФайл(ИмяФайла);

Сч = 0;
ТекОбъект = Неопределено;
Пока ЧтениеXML.Прочитать() Цикл
    Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
        //Сообщить("" + ЧтениеXML.ТипУзла + ":" + ЧтениеXML.Имя );
        Если ЧтениеXML.Имя = "item" Тогда
            Сч = Сч + 1;
            Если Сч % 100 = 0 Тогда
                Состояние(Сч);
            КонецЕсли;
            Если ТекОбъект <> Неопределено Тогда
                ТекОбъект.Записать();
                //Сообщить(ТекОбъект);
            КонецЕсли;
            ТекОбъект = Неопределено;

        ИначеЕсли ЧтениеXML.Имя = "link" Тогда
            ЧтениеXML.Прочитать();
            ТекСсылка = ЗначениеИзСтрокиВнутр(ЧтениеXML.Значение);
            ТекОбъект = ТекСсылка.ПолучитьОБъект();
        ИначеЕсли ЧтениеXML.Имя = "text" Тогда
            ЧтениеXML.Прочитать();
            Если ТекОбъект <> Неопределено Тогда
                ТекОбъект.Текст = ЧтениеXML.Значение;
            КонецЕсли;
        ИначеЕсли ЧтениеXML.Имя = "texth" Тогда
            ЧтениеXML.Прочитать();
            ТекЗначение = ЗначениеИзСтрокиВнутр(ЧтениеXML.Значение);
            //Сообщить("" + ТекОбъект + "" + ТекЗначение);
            Если ТекОбъект <> Неопределено Тогда
                ТекОбъект.ТекстХран = ТекЗначение;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Если ТекОбъект <> Неопределено Тогда
    ТекОбъект.Записать();
    //Сообщить(ТекОбъект);
КонецЕсли;

ЧтениеXML.Закрыть();

См. также

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

Комментарии

1. Ak A (frc) 12.07.12 14:40
А о чем статья? как блоками выгрузить данные в xml, т.к. "типовой" механизм, как всегда, не справился с объемом данных?
2. Ak A (frc) 12.07.12 14:41
И Сергей, есть же раскраска кода... Воспользуйтесь, не побрезгуйте :)
3. Осипов Сергей (fixin) 12.07.12 14:52
(2) воспользовался, не побрезговал, но он почему то весь код после раскраски вытянул в одну строку.
я запарился и оставил как есть.
Брал отсюда: http://www.oscomp.ru/1Color.php
4. Осипов Сергей (fixin) 12.07.12 14:53
(1) КЭП! ;-) именно. Ключевое слово - ЭТЮД. Слова-синонимы - мастер-класс, кейс и т.п.
5. Эдуард Зелинский (VasMart) 18.07.12 14:29
"Зачем нам готовое когда мы сами программисты?"
6. Осипов Сергей (fixin) 18.07.12 14:40
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа