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

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

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

Оффлайн Z.spb

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

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

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

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


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

 


   

 


Онлайн ilyay

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

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

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

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

Оффлайн Z.spb

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

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

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

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


Теги:
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

* Реклама

* Поиск

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

* Реклама

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

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

oleg-x
128 Сообщений
alex0402
63 Сообщений
AIFrame
56 Сообщений
MuI_I_Ika MuI_I_Ika
33 Сообщений
Kironten
28 Сообщений
Геннадий ОбьГЭС Геннадий ОбьГЭС
27 Сообщений
pavl_vs
26 Сообщений
Golickoff Golickoff
21 Сообщений
Александр Лахтин Александр Лахтин
18 Сообщений
xproh
17 Сообщений

* Кто онлайн

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

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

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

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

Поиск

 
SimplePortal 2.3.5 © 2008-2012, SimplePortal