Вся правда про властивістьБлокуватиДля Зміни, Стань експертом в 1С

властивістьблокуватидля

Мотивацією до написання цієї статті, послужила велика кількість помилок щодо якості «БлокуватиДля Зміни». Більшість матеріалів у мережі, присвячена або керованим блокуванням, або режиму поділу підсумків, властивість «БлокуватиДля Зміни» зачіпається лише частково без конкретики, в результаті у багатьох виникають питання при його використанні. Давайте розберемося, що це за звір і навіщо він взагалі потрібен.

Балаканина нічого не варта. Покажіть мені код.

Щоб зрозуміти матеріал цієї статті, потрібно добре знати і розуміти 2 речі:

1. Що таке режим поділу підсумків. Якщо ви раптом не знаєте, то рекомендую почитати цю статтю. Там все дуже докладно та зрозуміло написано.

2. Нова методика контролю залишків (залишки контролюються після запису)

Режим поділу підсумків дуже корисний у тому випадку, якщо не потрібно виконувати контроль залишків по регістру т.к. можна паралельно записувати дані з однаковим набором вимірів. Якщо з регістру необхіднозавжди контролювати залишки, краще не використовувати режим поділу підсумків т.к. виграшу у паралельності він не дає. Але як бути, якщо наприклад регістр має 2 реєстратори, і один документ використовує контроль залишків, а другий ні? У цьому випадку нам якраз і знадобиться властивість набору записів регістрів накопичення та бухгалтерії «БлокуватиДля Зміни».

Почнемо з того, що використовувати «БлокуватиДля Зміни» має сенс, тільки якщо виконуються всі наступні умови:

  • транзакція виконується в керованому режимі (якщо використовувати автоматично, то виникне помилка)
  • у регістру включено режим поділу підсумків (якщо він вимкнений, товластивість не має сенсу і просто ігноруватиметься)
  • використовується нова методика контролю залишків (залишки контролюються після запису)

Якщо хоча б одна з 3-х умов не виконується, то немає сенсу використовувати БлокуватиДля Зміни. Тому все сказане нижче застосовується тільки якщо виконуються всі три умови.

А що це властивість робить?

Ця властивість робить одну єдину річ, вона відключає роздільник підсумків по набору вимірювань, що записується, починаючи з моменту запису до кінця транзакції.

Деяких бентежить таке формулювання, а саме слова «відключає роздільник підсумків по набору вимірювань, що записується». Що б було зрозуміліше скажу іншими словами, якщо ми ставимо «БлокуватиДля Зміни» в «Істина», то кероване блокування накладається без урахування роздільника.

На мій погляд ці два формулювання однакові за змістом, але на іспиті 1С: Експерт рекомендую використовувати друге формулювання «кероване блокування накладається без урахування роздільника», хоча по суті вони описують те саме явище.

А детальніше?

Тут потрібно розписати кожну фразу, щоб виключити неправильне трактування.

«… воно відключає роздільник підсумків»

Незважаючи на назву, ця властивість фактично нічого не блокує, набір записів автоматично блокуються платформою при записі т.к. використовується керований режим. Справа в тому, що при використанні даної властивості, в момент блокування не враховуватиметься роздільник, якщо властивість не використовувати, то враховуватиметься роздільник.

Тобто блокування буде накладено в будь-якому випадку (незалежно від того чи використовуєте ви властивість чи ні), але при використанні «БлокуватиДля Зміни» блокування буде накладено без урахуванняроздільника підсумків.

А навіщо взагалі відключати роздільник підсумків?

Якщо не відключити роздільник підсумків, то платформа накладає керовану блокування за ключом Склад+Товар+Розділювач.

В результаті можливі такі наслідки:

  • При використанні СУБД блокування - можливе взаємоблокування.
  • При використанні версійника - можливе списання залишків мінус.

Давайте розберемо ці випадки докладніше.

Якщо використовується блокувальник.

У разі блокування, deadlock виходить досить просто, дві транзакції паралельно записують свої дані по одному набору вимірювань, платформа це дозволяє т.к. використовується роздільник підсумків. Після цього обидві транзакції хочуть перевірити залишки, а для цього потрібні всі рядки за ключом Склад+Товар (тобто без урахування роздільника). У результаті жодна з транзакцій неспроможна прочитати всі рядки, т.к. частина рядків захоплена іншою транзакцією (розділювач "заважає" захопити всі рядки).

Схема цієї взаємоблокування представлена ​​таблиці.

правда

У цьому випадку, за своїм призначенням, «БлокуватиДля Зміни» це аналог параметра «ДЛЯ ЗМІНИ» у запиті читання залишків в автоматичному режимі, тільки працює інакше.

Якщо увімкнути «БлокуватиДля Зміни», то ми відключимо роздільник підсумків, і при записі відразу буде накладено кероване блокування Склад+Товар, і транзакція 2 не зможе додати другий рядок, т.к. цей набір вимірів буде вже заблокований. При використанні «БлокуватиДля Зміни», блокування ключа Склад+Товар є наслідком відключення роздільника підсумків для запобігання дідлоку. Можна сміливо сказати, що це свого роду корисний побічний ефект.

Але навіть якби ми не використовувалиБлокувати для зміни (і ризикнули нарватися на deadlock), то залишки в мінус все одно б не списалися, т.к. всі потрібні рядки по ключу Склад+Товар (без урахування роздільника) були б заблоковані запитом залишків.

Багато плутанини виникає через назву цієї властивості, тому відразу незрозуміло як воно працює. У цьому випадку назва не відповідає тому, що властивість робить насправді (вона нічого не блокує, вона відключає роздільник), але назва відповідає отриманому результату (в результаті отримуємо блокування по всіх потрібних записах).

Якщо використовується версійник

У цьому випадку, заблоковані рядки першої транзакції, ніяк не завадять 2-й транзакції прочитати залишки (т.к. у версійнику не блокують читачів). Друга транзакція спокійно прочитає стару версію даних (версію на момент початку першої транзакції) і спише залишок мінус. Щоб цього не допустити потрібне кероване блокування на рівні 1С. Якщо поставити БлокуватиДля Зміни = Істина, ми отримаємо таке блокування, і дані будуть заблоковані на рівні платформи.

«за набором вимірювань, що записується»

Роздільник вимикається лише для цього набору вимірювань.

Це означає, що режим поділу підсумків на регістр у цілому зберігається і якщо в інших наборів вимірювань БлокуватиДля Зміни = Брехня, то вони можуть бути записані паралельно.

Припустимо, що одночасно зустрілися 6 транзакцій і спробували одночасно записати дані в регістр, при цьому роздільник підсумків природно включений. Перші 2 транзакції роблять витрату та контролюють залишки, інші 4 роблять прихід і контроль залишків їм не потрібен.

Тоді ми отримаємо таку картину.

Транзакція 1 виявилася на секунду швидше за всіх і вмомент запису даних встановила виняткову керовану блокування без урахування роздільника підсумків (т.к. БлокуватиДля Зміни = Істина). Транзакції 2 і 6 чекають на транзакцію 1, т.к. набір вимірів вони однаковий. У даному випадку без різниці яке значення «БлокуватиДля Зміни» встановлено для транзакцій 2 і 6, важливо, що набір вимірювань однаковий, і він вже заблокований, так що вони не зможуть паралельно записати свої дані. Транзакції 3 та 4 успішно записали свої дані паралельно, т.к. увімкнено роздільник (БлокуватиДля Зміни = Брехня). Транзакція 5 успішно записала дані паралельно, т.к. використовується відмінний від транзакції 1 набір вимірів.

«починаючи з моменту запису до кінця транзакції»

Розділювач підсумків відключається тільки в той момент, коли починається запис даних регістру та діє доти, доки не закінчиться транзакція проведення документа. Це означає, що включити дану властивість можна в будь-якому місці коду, але діяти вона почне тільки в момент запису даних в регістр. При цьому властивість діє, доки завершилася вся транзакція, тобто. якщо запис у регістр завершилася, а транзакція продовжується, то властивість як і продовжує працювати. Таким чином, якщо відбудеться відкат транзакції, властивість автоматично набуде значення «Брехня»

А що буде, якщо встановити БлокуватиДля Зміни = Істина для регістру, у якого вимкнено режим поділу підсумків?

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

А як же явні керовані блокування, вони тепер не потрібні?

Так, це ще один плюс цієї якості. При його використанні не потрібно писати явні керовані блокування, достатньо одного рядкаРухи.ПотрібнийРегістр.БлокуватиДля Зміни = Істина, це робить код компактнішим і читабельнішим. Але варто пам'ятати, що використовувати дану властивість можна тільки при дотриманні трьох умов, описаних на початку статті.

А чи можна приклад?

Допустимо, є документ реалізація, який робить рух по одному регістру з контролем залишків, при цьому по даному регістру включено роздільник підсумків.

У такому разі код модуля проведення виглядатиме так:

Рядок «Руху.ЗалишкиТоварів.БлокуватиДля Зміни = Істина;» можна писати будь-де процедури, для зручності краще це робити наприкінці.

Код з перевіркою залишків, так само можна написати в модулі набору записів регістру, але в цьому випадку потрібно перевірити тип документа, т.к. можливо, для деяких документів контроль не потрібен.

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

Висновки:

1. Дану властивість потрібно використовувати тільки якщо дотримуються всі 3 умови:

  • транзакція виконується у керованому режимі
  • у регістру включено режим поділу підсумків
  • використовується нова методика контролю залишків (залишки контролюються після запису)

2. Незважаючи на назву, властивість нічого не блокує (блокування відбувається при записі в будь-якому випадку), воно відключає режим поділу підсумків, наслідком є ​​блокування всіх потрібних записів (без урахування роздільника).

3. При використанні «БлокуватиДля Зміни» явні керовані блокування ставити не потрібно.