Реклама на этом месте
Форум 1С
Форум 1С
Программистам. Бухгалтерам. Администраторам. Пользователям
Задай вопрос - получи решение проблемы. Без троллинга и флуда.
06 Дек 2016, 20:50
МультиВход
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?
 
collapse

Автор Тема: Блокировка при записи в регистр сведений.  (Прочитано 308 раз)

0 Пользователей и 2 Гостей просматривают эту тему.

Оффлайн Z.spb

  • *
  • Сообщений: 4
  • РЕПУТАЦИЯ: 0
  • Регистрация: 2016-10-03
  • Сайт: 
  • Профессия: Программист 1С
Просьба сильно не пинать. Не так давно занимаюсь 1С, во всех нюансах ещё не разобрался :dfbbdrfb:.
УПП 8.2 Обычное приложение. Режим блокировок в свойствах конфигурации - управляемый.

Исходные данные: В общем модуле сделана подписка перед записью некоторых справочников. Создан регистр сведений (непериодический, независимый),
измерения:
Объект (тип УникальныйИдентификатор); Номер (тип Число).
ресурс: ДопСведения (которые нужно сохранить)
реквизит: ДатаЗаписи.
Перед записью объекта делаю запрос:
	| ВЫБРАТЬ ЕСТЬNULL(МАКСИМУМ(Номер), 0) КАК Номер
| ИЗ РегистрСведений.<ИмяРегистра>
| ГДЕ Объект = &УИД"; //(уникальный идентификатор)
Выборка = Запрос.Выполнить().Выбрать(); Выборка.Следующий();
x = РегистрыСведений.<ИмяРегистра>.СоздатьМенеджерЗаписи();
x.Объект = УИД;
x.Номер = Выборка.Номер + 1; // - это обеспечивает уникальность записи
x.ДатаЗаписи = ТекущаяДата();
x.ДопСведения = <тут идут нужные мне данные>;
x.Записать();

Далее. Раз в полчаса мне нужно оперативно сливать эти доп. данные в отдельную базу. Сделал фоновое задание.
Чтобы брать только записи, транзакция по которым точно завершилась, написал запрос к SQL серверу, который возвращает мне дату самой давней активной транзакции. Если активных транзакций в данный момент нет, то возвращается текущаядата(). Записи из регистра читаю только те, которые младше по дате
ВЫБРАТЬ * ИЗ РегистрСведений.<ИмяРегистра> ГДЕ ДатаЗаписи < &ДатаНачалаПоследнейАктивнойТранзакции
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий()....
<идёт обработка выборки, передача по внешнему соединению в другую базу там создаётся по каждой записи отдельный документ>
//если всё прошло без ошибок то
Набор = РегистрыСведений.<ИмяРегистра>.СоздатьНаборЗаписей();
Набор.Отбор.Объект.Установить(Выборка.Объект);
Набор.Отбор.Номер.Установить(Выборка.Номер);
//не прочитав записываю, т.е. стираю обработанную строчку из регистра
Набор.Записать();

Как то так. Неделю эта хрень работала в нагруженной базе без ошибок, фоновое задание отрабатывало как надо. Недавно была массовая операция записи объектов (периодически у нас бывает получение данных из других программ и т.д), всё выполнялось в одной длительной транзакции, которая длилась более часа. Фоновое задание стартовало 2 раза в этот период и оба раза свалилось с ошибкой:
Ошибка при вызове метода контекста (Записать): Конфликт блокировок при выполнении транзакции:
Превышено максимальное время ожидания предоставления блокировки


Если кто-то может объяснить, откуда взялась блокировка, буду признателен. Я же считывают только те записи запросом, которые были записаны ДО момента начала транзакции. А значит они должны быть не заблокированы? :dfbbdrfb:
(ps. как только длительная транзакция завершилась следующее фоновое задание отработало без ошибок)

 


   

 

Смотрите бесплатно более 300 видеоуроков по работе в 1С:Бухгалтерия 8 и 1C:ЗУП 8 ред. 3.0

СМОТРЕТЬ >>


Оффлайн ilyay

  • 1С:Специалист, 1С:Эксперт
  • ***
  • Сообщений: 173
  • РЕПУТАЦИЯ: 24
  • КПД: 14%
  • Регистрация: 2011-06-09
  • Сайт: 
  • Профессия: Разработчик 1С
Во-первых, если транзакция завершилась, то данные есть, а если не завершилась, их нет. Промежуточного состояния не может быть.

Не проверяйте время окончания транзакции (это технологически неверно). Вы видите, что транзакция закончилась, лезете в базу, а в этот момент там параллельно началась другая транзакция.

Если режим блокировок управляемый, тогда устанавливайте их явно: БлокировкаДанных = Новый БлокировкаДанных и т.д.
Скорее всего, взаимная блокировка возникает, потому что вы не блокируете данные (в режиме исключительно), которые собираетесь изменять, до чтения их запросом. Надо Заблокировать-Прочитать-Записать в транзакции.
Добавлено: 03 Окт 2016, 15:15

Блокировка может накладываться на более широкие диапазоны данных, вплоть до таблицы целиком. Настройте технологический журнал для отображения события TLOCK, например, чтобы увидеть как накладываются блокировки в вашем случае.

Оффлайн Z.spb

  • *
  • Сообщений: 4
  • РЕПУТАЦИЯ: 0
  • Регистрация: 2016-10-03
  • Сайт: 
  • Профессия: Программист 1С
Спасибо за ответ. Но вот про это я не понял
Во-первых, если транзакция завершилась, то данные есть, а если не завершилась, их нет. Промежуточного состояния не может быть.
Как не может? Вот я беру тестовую базу, открываю в двух экземплярах. В одном окне запускаю любую длительную транзакцию, ну просто для примера
НачатьТранзакцию();
Ном = Справочники.Номенклатура.Выбрать();
сч=0;
Пока Ном.Следующий() И сч<10000 Цикл
сч = сч + 1;
Об=Ном.ПолучитьОбъект();
        Об.Наименование = Об.Наименование + "1234";
Об.Записать();
КонецЦикла;
ОтменитьТранзакцию();

Процесс пошёл. Система начинает массово перезаписывать номенклатуры. Каждый раз срабатывает моя подписка "Перед записью", она получает нужные мне доп.данные, пишет их в регистр. Если в это время во втором окне открыть консоль запросов и написать мой запрос из фонового задания (ВЫБРАТЬ * ИЗ РегистрСведений.<ИмяРегистра>) то данные вполне себе есть. Я могу их спокойно считывать, обрабатывать, и пересылать "кривые" наименования с "1234" в другую базу. И это не смотря на то, что транзакция ещё не завершилась. Когда же транзакция отменится все записи из регистра исчезнут, как будто их там и не было. Но всё то время, что шла транзакция, они там были и были доступны для чтения... И если фоновое задание в этот период сработает то оно их прочитает и перешлёт неверные наименования. Разве нет? 

Не проверяйте время окончания транзакции (это технологически неверно). Вы видите, что транзакция закончилась, лезете в базу, а в этот момент там параллельно началась другая транзакция.
Я получаю время не окончания, а начала самой ранней из активных транзакций. Именно из-за того что я описал выше я и решил отделить те записи, по которым транзакция, возможно, ещё не завершена (и они могут впоследствии "исчезнуть" из регистра, если транзакция к которой они относятся будет отменена) и те, которые уже ТОЧНО зафиксированы.

Если режим блокировок управляемый, тогда устанавливайте их явно: БлокировкаДанных = Новый БлокировкаДанных и т.д.
Я читал про эту возможность, но, честно говоря, никогда не ставил блокировки данных вручную. У нас есть несколько "самописных" регистров, куда пишутся данные, нигде ничего подобного не написано насчёт блокировок. Всё работает. Попробую, если ничего другого не получится.

Скорее всего, взаимная блокировка возникает, потому что вы не блокируете данные (в режиме исключительно), которые собираетесь изменять, до чтения их запросом. Надо Заблокировать-Прочитать-Записать в транзакции.
Спасибо, попробую. А если я заблокирую все записи в регистре, а в этот момент сработает очередное "ПередЗаписью" и запрос   | ВЫБРАТЬ ЕСТЬNULL(МАКСИМУМ(Номер), 0) КАК Номер
    | ИЗ РегистрСведений.<ИмяРегистра>" попытается прочитать этот регистр, то что будет? Не будет ли в этом случае ошибка, из-за того что регистр не доступен для чтения?

Добавлено: 04 Окт 2016, 16:15

Ну вот. Я разобрался где ошибка, всё оказалось проще, чем я думал. Ошибся я в запросе к SQL серверу. Он возвращает дату начала транзакции иногда как дату, а иногда как строку!, в формате месяц-день-год-время-PM\AM. Почему так, я пока не понял. Когда тестировал на отладке всегда возвращалась дата-время. Отсюда урок - нужно в подобных запросах не забывать писать CONVERT(datetime,<Дата>,13). А в 1С проверять ТипЗнч, которое я получил. Потому что 1С запросу с условием "ГДЕ ДатаВерсии < &ДатаВерсии" всё равно что я ему подсунул дату или любую абракадабру в виде строки. Он всё равно выполняется без ошибок, только ничего не фильтурет и выдаёт все записи. Поэтому и блокировка, что я пытался стереть записи, по которым ещё шла транзакция.

Последний раз редактировалось: Z.spb; 04 Окт 2016, 16:15. Причина: Объединение сообщений

Оффлайн ilyay

  • 1С:Специалист, 1С:Эксперт
  • ***
  • Сообщений: 173
  • РЕПУТАЦИЯ: 24
  • КПД: 14%
  • Регистрация: 2011-06-09
  • Сайт: 
  • Профессия: Разработчик 1С
Цитировать
Если в это время во втором окне открыть консоль запросов и написать мой запрос из фонового задания (ВЫБРАТЬ * ИЗ РегистрСведений.<ИмяРегистра>) то данные вполне себе есть.
Это "грязные данные", т.е. данные не завершенной транзакции. Это особенность файловой версии. На сервере может быть по-другому, в зависимости от настроек. Открывайте транзакцию, а потом читайте.

Сейчас вы читаете без транзакции. Блокировки учитываются только при работе транзакции. "Грязные данные" появляются, когда СУБД работает в режиме версионирования, а запрос на чтение вне транзакции. Когду СУБД работает как блокировочная (например, на 8.2 или 8.3 с автоматическими блокировками), там не будет такого эффекта.
Добавлено: 05 Окт 2016, 11:48

Цитировать
Не будет ли в этом случае ошибка, из-за того что регистр не доступен для чтения?
Будет ожидание на блокировках, т.е. система будет ждать, когда блокировки будут сняты и она сможет прочитать данные. Если ожидание будет слишком долгим, произойдет отмена транзакции из-за таймаута.
Добавлено: 05 Окт 2016, 11:50

Делайте чтение в транзакции, и тогда в отладчике вы увидите, что система ждет, пока параллельный процесс отпустит блокировки (по фиксации либо отмене транзакции).


Теги:
 

Отличие проводки по регистру сведений от проводки по регистру накопления?

Автор DirecTwiXРаздел Конфигурирование, программирование в "1С - Предприятие 8"

Ответов: 2
Просмотров: 2637
Последний ответ 18 Апр 2012, 02:19
от Dethmontt
Добавление сведений в графу "основание" документа "ТОРГ-12"

Автор Ярослав1984Раздел Конфигурирование, программирование в "1С - Предприятие 8"

Ответов: 4
Просмотров: 4650
Последний ответ 20 Авг 2013, 18:45
от Ярослав1984
Как можно подставлять цену из регистра сведений "Цены поставщиков" в документ"ПоступлениеТоваров" на актуальную дату? Необходимо использовать запрос в решении.

Автор Елена6666666666Раздел Конфигурирование, программирование в "1С - Предприятие 8"

Ответов: 14
Просмотров: 5232
Последний ответ 24 Окт 2014, 13:30
от cska-fanat-kz
Проверка на "новую" запись в рег. сведений

Автор nomer13Раздел Конфигурирование, программирование в "1С - Предприятие 8"

Ответов: 6
Просмотров: 9685
Последний ответ 11 Янв 2011, 10:04
от nomer13
Регистры накопления, Регистры сведений, Документы, Проведение

Автор kot_ooРаздел Конфигурирование, программирование в "1С - Предприятие 8"

Ответов: 12
Просмотров: 4960
Последний ответ 17 Янв 2014, 21:52
от kot_oo

* Живое общение

Не устроил ответ?

Зарегистрируйся и задай свой вопрос. Живое общение приносит результат намного быстрее.


Зарегистрироваться

* Реклама

* Поиск

* Последние задачи на разработку (фриланс)

* Реклама

* Последние вакансии

* Топ 10 авторов за месяц

MuI_I_Ika MuI_I_Ika
77 Сообщений
cska-fanat-kz cska-fanat-kz
67 Сообщений
Kironten
42 Сообщений
alex0402
42 Сообщений
alexandr_ll
34 Сообщений
LexaK
33 Сообщений
Андрей1966
26 Сообщений
djkeysi
24 Сообщений
sertak sertak
22 Сообщений
BuhRust
20 Сообщений

* Кто онлайн

  • Точка Гостей: 268
  • Точка Скрытых: 0
  • Точка Пользователей: 6
  • Точка Сейчас на форуме:

* Облако тэгов

* Форум 1С с мобильного

* Инструменты

* Дополнительно

Поиск

 

Dellos Catering - выездной ресторан кейтеринг по всему Миру
SimplePortal 2.3.5 © 2008-2012, SimplePortal