Довідковий матеріал

Блокування даних у 1С:Підприємстві 8

1. Що таке блокування даних і навіщо воно потрібнеКороткий зміст:. Що таке блокування. Об'єктні та транзакційні блокування. Механізм об'єктних блокувань. Об'єктне песимістичне блокування. Об'єктне оптимістичне блокування. Механізм транзакційних блокувань. Загальні відомості про транзакції та блокування СУБД. Рівні ізоляції транзакцій. Режим автоматичних блокувань. Режим керованих блокувань. Встановлення режиму керування блокуваннями для об'єктів конфігурації. Встановлення керованих блокувань. Рекомендації щодо модифікації конфігурацій під час переходу до режиму керованих блокувань

Блокування даних у 1С:Підприємстві 8

Короткий зміст:

Що таке блокування

Об'єктні та транзакційні блокування

Механізм об'єктних блокувань

Об'єктне песимістичне блокування

Об'єктне оптимістичне блокування

Механізм транзакційних блокувань

Загальні відомості про транзакції та блокування СУБД

Рівні ізоляції транзакцій

Режим автоматичних блокувань

Режим керованих блокувань

Встановлення режиму керування блокуваннями для об'єктів конфігурації

Встановлення керованих блокувань

Рекомендації щодо модифікації конфігурацій під час переходу до режиму керованих блокувань

 

Короткий зміст:

1. Що таке блокування даних і навіщо воно потрібне

2. Об'єктні блокування

3. Транзакційні блокування

4. Автоматичні транзакційні блокування

5. Керовані транзакційні блокування

6. Переведення конфігурації в режим керованих блокувань

Ця стаття є фрагментом книги П.С.Бєлоусов, А.В.Островерх "1С:Підприємство: від 8.0 до 8.1".
Дата виходу книги: листопад 2007.

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

Опису проблем, що виникають, а також шляхів їх вирішення в системі 1С:Підприємство 8.1 і присвячена ця стаття.

Що таке блокування

Перш ніж почати вивчення механізмів 1С:Підприємства, що забезпечують конкурентний доступ користувачів до даних, ознайомимося з тим, що таке блокування, коли воно виникає і чи можна обійтися без блокувань.

У загальному випадку блокування — це інформація про те, що цей ресурс захоплений «кимось» для виконання якоїсь дії.

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

Прийшов покупець Іванов і йому сподобалося яблуко №4. Він хоче його купити. Іванов дістає гаманець і відраховує гроші (рис. 1).

Рис. 1. Иванов хочет купить яблоко №4:

Рис. 1. Іванов хоче купити яблуко №4

Тим часом продавець робить запис у своїй книзі: «Яблуко №4 — продано Іванову». Цей запис і є блокуванням (рис. 2).

Рис. 2. Продавец «заблокировал» яблоко №4:

Рис. 2. Продавець «заблокував» яблуко №4

Зверніть увагу, що насправді яблуко все ще перебуває у продавця, Іванов його не купив. Може, й не зможе купити (наприклад, виявиться, що не вистачає грошей). Але у продавця вже записано, що це яблуко не можна пропонувати іншим покупцям доти, доки Іванов не завершить процес купівлі. Цей процес, що складається з кількох взаємопов'язаних дій (вибір яблука, відрахування грошей, передача грошей продавцю, передача яблука покупцеві), називається транзакцією. Блокування має бути встановлене в момент вибору Івановим яблука №4 і зняте після завершення транзакції купівлі.

Тим часом підходить Петров і теж хоче купити яблуко. Він зможе купити будь-яке яблуко, крім яблука №4 (рис. 3).

Рис. 3. Петров сможет купить любое яблоко, кроме яблока №4: I I л.

Рис. 3. Петров зможе купити будь-яке яблуко, крім яблука №4

Таким чином сенс блокування полягає в тому, щоб заборонити деякі дії над спільним ресурсом на певний обмежений час. У цьому випадку Петрову заборонено вибирати яблуко №4 доти, доки Іванов не завершив свою транзакцію купівлі. Тобто Петров перебуває у стані очікування на блокуванні.

З наведеного прикладу зрозуміло, що блокування — це необхідний механізм за конкурентного доступу до спільних ресурсів. Справді, що було б, якби продавець не записав у своїй книзі, що яблуко з четвертої комірки не можна пропонувати іншим покупцям? Найімовірніше, стався б конфлікт між Івановим і Петровим, можливо, при цьому «дісталося» б і продавцю. У будь-якому разі, якщо запис у книзі продавця відсутній, результат цієї ситуації стає непередбачуваним. Невідомо, кому дістанеться це яблуко, невідомо, у кого опиняться гроші, які Іванов за нього віддав, і так далі.

Якщо ж блокування на яблуко №4 встановлено, то це гарантує однозначний результат: Іванов гарантовано зможе купити яблуко, якщо в нього вистачить грошей. Якщо ж він відмовиться від купівлі, то лише в цьому разі яблуко з 4 комірки зможе купити Петров.

Слід розуміти, що через різні причини блокування можуть бути як «хорошими» (необхідними), так і «поганими» (надмірними).

Розглянемо ще один варіант розвитку подій, який пояснює, звідки беруться «погані» блокування.

Покупець Іванов хоче купити одне яблуко. Він перебирає всі яблука з ящика по одному, вибираючи, яке краще. При цьому продавець записує у своїй книзі всі яблука, які сподобалися Іванову (рис. 4).

Рис. 4. Продавец блокирует все яблоки, которые нравятся Иванову: V 2________/ 2

Рис. 4. Продавець блокує всі яблука, які подобаються Іванову

У цей час підходить Петров і не може купити жодного яблука, тому що вони всі заблоковані Івановим (рис. 5).

Рис. 5. Петров не может купить ни одного яблока: Иванов Петров J

Рис. 5. Петров не може купити жодного яблука

Петров чекає деякий час, ображається та йде (рис. 6). Ця подія відповідає помилці "Перевищення часу очікування блокування".

Рис. 6. Петров не дождался и ушел: V 2________/ 2

Рис. 6. Петров не дочекався і пішов

А Іванов у результаті вибирає одне-єдине яблуко (найкраще) і купує тільки його (рис. 7).

Рис. 7. Иванов покупает только одно яблоко:

Рис. 7. Іванов купує тільки одне яблуко

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

У цьому випадку (на відміну від першого прикладу) Петров якраз зіткнувся з «поганими» (надмірними) блокуваннями.

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

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

Об'єктні та транзакційні блокування

У системі 1С:Підприємство 8 існують два механізми, під час роботи яких використовується термін блокування. Часто це призводить до плутанини й дозволяє думати, що йдеться про одні й ті самі блокування або про один і той самий механізм. Насправді це не так. Кожен із цих механізмів призначений для забезпечення конкурентної роботи користувачів, проте у своїй визначеній сфері, і при цьому блокування, що використовуються одним та іншим механізмами, мають цілком різний зміст (рис. 8).

Рис. 3.8. Объектные и транзакционные блокировки:  Объектные блокировки Оперативная память Платфор /ла 1С:Предприятие 8 СУБД Транзакционные блокировки

Рис. 8. Об'єктні та транзакційні блокування

Логічна модель даних 1С:Підприємства 8 передбачає, що на самому «верхньому» рівні абстракції користувач має справу з об'єктами системи як сукупністю неподільних даних. Такими об'єктами, наприклад, є елементи довідників, документи тощо. Елемент довідника може містити велику кількість реквізитів, кілька табличних частин, але всі ці дані необхідно змінювати одночасно та узгоджено. Механізм об'єктних блокувань саме й дозволяє здійснювати конкурентний доступ користувачів до даних 1С:Підприємства в термінах об'єктів інформаційної бази. Як правило, у більшості випадків це пов'язано з інтерактивною роботою користувачів у формах: редагуванням наявних об'єктів, видаленням, створенням нових тощо.

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

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

Далі розглянемо роботу цих двох механізмів докладніше.

Механізм об'єктних блокувань

Об'єктне песимістичне блокування

Песимістичне блокування об'єктів бази даних призначене для того, щоб заборонити зміну даних певного об'єкта іншими сеансами або цим сеансом доти, доки блокування не буде зняте цим об'єктом вбудованої мови.

Переважно механізм песимістичного блокування використовується системою 1С:Підприємство 8.1 для блокування об'єктів, що редагуються у формі. У той момент, коли користувач починає модифікацію об'єкта у формі, розширення форми встановлює песимістичне блокування. Якщо після цього інший користувач, наприклад, спробує виконати редагування того самого об'єкта, йому буде видано повідомлення про те, що не вдалося заблокувати об'єкт. Коли користувач, який редагував об'єкт, закриє форму об'єкта, розширення форми зніме песимістичне блокування.

Розглянемо приклад. Увійдемо в інформаційну базу, що додається до роботи, під користувачем Іванов, відкриємо форму елемента 1С:Підприємство 8.0. Управління торгівлею довідника Номенклатура (код 12) і змінимо ціну продажу з 420,00 на 450,00. Не зберігаючи внесені зміни, увійдемо в інформаційну базу ще раз, але тепер під ім'ям користувача Петров. Відкриємо форму того самого елемента довідника та спробуємо змінити значення будь-якого реквізиту. Будь-яка спроба зміни призведе до появи спеціального вікна з повідомленням про помилку (рис. 9):

Рис. 3.9. Пример работы пессимистической блокировки:

Рис. 9. Приклад роботи песимістичного блокування

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

Водночас розробник має можливість задіяти розглянутий механізм, використовуючи засоби вбудованої мови. Для того щоб встановити песимістичне блокування об'єкта, можна використовувати метод об'єкта Заблокувати().

УВАГА
Важливою відмінністю версії 8.1 платформи 1С:Підприємство є те, що сам по собі факт встановлення блокування не перешкоджає зміні або видаленню об'єкта в базі даних. Тому для того, щоб забезпечити неможливість зміни заблокованого об'єкта, операції зміни об'єкта в іншому сеансі також має передувати спроба блокування того самого об'єкта. Блокування заблокованого об'єкта бази даних викликає виняток, який може бути оброблений конструкцією Спроба ... Виняток ... КінецьСпроби.

Для зняття песимістичного блокування розробник може використовувати метод об'єкта Розблокувати(), причому використовувати його для того самого екземпляра об'єкта, для якого раніше було встановлено блокування.

Розглядаючи можливість взаємного впливу механізмів об'єктних і транзакційних блокувань, нагадаємо, що об'єктні блокування не впливають на операції над даними та на процес перебігу транзакцій (зверніть увагу: на рис. 8 вони розташовані на різних рівнях роботи з даними). Якщо блокування об'єкта викликало виняток, то він, як було зазначено вище, може бути оброблений розробником конфігурації та не призведе до обов'язкового відкоту транзакції. З іншого боку, блокування об'єктів, встановлені протягом транзакції, зберігаються під час фіксації транзакції та знімаються під час відкоту транзакції.

Об'єктне оптимістичне блокування

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

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

Розглянемо приклад. Відкриємо два сеанси роботи з інформаційною базою, що додається до роботи: один під користувачем Іванов, а інший — під користувачем Петров. В обох сеансах відкриємо форму елемента Управління торгівлею довідника Номенклатура (код 12). Тепер у сеансі, відкритому від імені користувача Іванов, змінимо ціну продажу з 420,00 на 450,00 і запишемо внесені зміни. Після цього в сеансі, відкритому від імені користувача Петров спробуємо змінити значення будь-якого реквізиту. Будь-яка спроба зміни призведе до появи іншого вікна з повідомленням про помилку (рис. 10):

Рис. 3.10. Пример работы оптимистической блокировки: Е Номенкл...:Предприятие 8.0. Управление торговлей _ П X Действия _4 [Щ] Перейти I Код: Наименование: 1 С: Предприятие Операция не может быть выполнена из-за несоответствия версии или отсутствия записи базы данных возможно, запись была изменена или удалена

Рис. 10. Приклад роботи оптимістичного блокування

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

Механізм транзакційних блокувань

Загальні відомості про транзакції та блокування СУБД

Перш ніж перейти до розгляду механізмів платформи 1С:Підприємство, ознайомимося загалом із поняттями, які буде використано далі.
Поняття транзакційного блокування нерозривно пов'язане з поняттям транзакції.

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

Можливі проблеми за багатокористувацького доступу до тих самих даних

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

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

  • Проблема втраченого змінення (англ. The Lost Update Problem) — якщо дві транзакції змінюють одні й ті самі дані, взявши як першоджерело початкове значення цих даних, то в системі залишаться зміни, внесені тією транзакцією, яка записала свої зміни останньою, оскільки ці зміни замінять собою всі зміни, внесені до цього.

Приклад. Розглянемо такий приклад. Припустімо, у довіднику Номенклатура, Транзакція №1 звернулася до елемента 1С:Підприємство 8.0. Управління торгівлею і вирішила змінити значення реквізиту ЦінаПродажу з 420 на 450. Одночасно Транзакція №2 вирішила у цього ж товару змінити значення реквізиту ОдиницяВиміру з Штука на Коробка. Розподіл у часі описаних дій показано на рис. 11. Таким чином в елементі довідника залишилися тільки ті зміни, які зробила Транзакція №2.

Висновок. Не можна одночасно змінювати одні й ті самі дані;

Рис. 3.11. Иллюстрация проблемы последнего изменения: Транзакция 1 Транзакция 2

Рис. 11. Ілюстрація проблеми втраченого змінення

  • Проблема «брудного» читання (англ. The Uncommitted Dependency Problem) — якщо одна транзакція почне зчитувати деякі дані, не дочекавшись завершення внесення змін, що вносяться до цих даних іншою транзакцією, то досить імовірний випадок, коли прочитані дані міститимуть неправильну інформацію.
Приклад. Повернімося до прикладу, розглянутого вище. Припустімо, у довіднику Номенклатура, Транзакція №1 звернулася до елемента 1С:Підприємство 8.0. Управління торгівлею і змінила значення реквізиту ЦінаПродажу з 420 на 450. Не дочекавшись фіксації змін, Транзакція №2 використала значення реквізиту для визначення суми продажу. Однак перша транзакція вирішила не зберігати внесені зміни (відкат транзакції) та відновила старі дані. Графічне подання дій транзакцій показано на рис. 12. Таким чином Транзакція №2 у своїх розрахунках використала дані, яких не існує в системі.Висновок. Не можна читати вже змінені, але ще не записані дані.

Рис. 3.12. Иллюстрация проблемы «грязного» чтения: Транзакция 1 Транзакция 2

Рис. 12. Ілюстрація проблеми «брудного» читання

  • Проблема неповторюваного читання (англ. The Inconsistent Analysis Problem) — якщо одна транзакція кілька разів зчитує одні й ті самі дані, а друга — вносить зміни до цих даних між циклами читання даних першої транзакції, то під час повторного зчитування перша транзакція може отримати інший набір даних.

Приклад. Припустімо, у нашому прикладі Транзакція №1 два рази поспіль звертається до елемента довідника 1С:Підприємство 8.0. Управління торгівлею і щоразу зчитує значення реквізиту ЦінаПродажу. Якщо в проміжок між першим і другим читанням вклиниться Транзакція №2 та змінить значення цього реквізиту, то в результаті вийде, що перша транзакція працює з даними, які з її точки зору мимовільно змінюються. Графічне подання цієї проблеми показано на рис. 13.

Висновки. Не можна повторно читати змінені та записані дані, якщо ці ж самі дані вже були прочитані до внесення до них змін;

Рис. 3.13. Иллюстрация проблемы неповторяемого чтения: Транзакция 1 Транзакция 2

Рис. 13. Ілюстрація проблеми неповторюваного читання

  • Проблема читання фантомів (англ. The Phantom Read Problem) — якщо перша транзакція зчитує дані й потім на їх основі здійснює певні дії, а друга транзакція в цей момент додає до цих даних нову інформацію, то, як і в попередньому випадку, це може призвести до некоректного результату.

Приклад. Припустімо, компанія займається продажем товарів і складається з кількох відділів. У разі, коли обсяг продажів працівників одного відділу перевищує 1000 рублів, то кожен працівник відділу отримує премію 20 % від суми своїх продажів. В іншому разі розмір премії становить 10 %. Очевидно, що процес нарахування премії працівникам кожного відділу складатиметься з кількох операцій:

  • отримання загальної суми продажів по відділу загалом шляхом підсумовування окремих продажів кожного з працівників;
  • визначення на підставі отриманих даних відсотка премії;
  • розрахунку суми премії для кожного з працівників відділу.

Припустімо, що дані про продажі вводить Транзакція №2, а розмір премії розраховує Транзакція №1. Тоді за одночасної роботи транзакцій може виникнути ситуація, показана на рис. 14. Таким чином Транзакція №1 у двох однакових вибірках рядків отримала різні результати.

Висновки. Не можна вводити нові дані (видаляти наявні), якщо вони можуть потрапити до вже один раз прочитаних даних під час повторного читання.

Рис. 3.14. Иллюстрация проблемы фантомов: rarere aredjL rarereoredjL

Рис. 14. Ілюстрація проблеми фантомів

Строго кажучи, список перелічених вище проблем не є остаточним.

Рівні ізоляції транзакцій

Отже, заради збільшення продуктивності системи ми повинні допустити паралельне виконання транзакцій. При цьому ми також повинні забезпечити необхідний нам ступінь цілісності даних (тобто обмежити паралельність транзакцій під час роботи з одними ресурсами). Суворість цих обмежень може бути різною, залежно від розв'язуваного завдання. Тому нам потрібен механізм гнучкого налаштування цих обмежень. У сучасних СУБД така можливість реалізується шляхом застосування рівнів ізоляції транзакцій. Наприклад, MS SQL Server 2000 дозволяє використовувати такі рівні ізоляції транзакції:

  • READ UNCOMMITED — незавершене читання. Найнижчий рівень ізоляції, забезпечує максимальну паралельність виконання транзакцій. Цей рівень захищає дані, що змінюються мною, від змін, які можуть внести конкуруючі транзакції. Якщо іншій транзакції необхідно змінити ті самі дані, то вона повинна очікувати завершення змінення даних моєю транзакцією. Однак читання даних дозволене. Таким чином цей рівень ізоляції допускає читання незавершених змін даних.
  • READ COMMITED — забезпечує заборону «брудного» читання. Якщо моя транзакція почала змінювати дані, то конкуруюча транзакція не може не тільки змінити, а навіть прочитати їх до завершення моїх змін. Після того, як мої зміни завершені, конкуруючі транзакції можуть читати дані, не чекаючи завершення моєї транзакції загалом. Таким чином існує проблема неповторюваного читання.
  • REPEATABLE READ — забезпечує повторюваність читання даних. Якщо моя транзакція починає читати дані, то інша транзакція не може їх змінити до завершення моєї транзакції.
  • SERIALIZABLE — послідовне виконання. Цей рівень ізоляції є максимальним і забезпечує повну ізоляцію транзакцій одна від одної. Вирішуються всі розглянуті проблеми, включно з проблемою «фантомів».

Залежно від використовуваного рівня ізоляції, СУБД накладає різні типи блокувань на різні об'єкти бази даних на різний час.

Режим автоматичних блокувань

Режим автоматичних блокувань у 1С:Підприємстві 8.1 повністю аналогічний механізму транзакційних блокувань, що використовувався у версії 8.0. У цьому режимі 1С:Підприємство цілком «покладається» на можливості, що надаються СУБД (рис. 15).

Рис. 3.15. Атоматические блокировки в транзакции 1С:Предприятия 8: 1С:Предприятие 8.0/8.1 СУБД

Рис. 15. Автоматичні блокування в транзакції 1С:Підприємства 8

Такий підхід дозволяє розробнику не замислюватися над досить складними питаннями блокування потрібних даних у транзакції. Однак СУБД не має інформації про логічну структуру даних 1С:Підприємства, і платформі доводиться використовувати досить високі рівні ізоляції транзакцій СУБД для того, щоб забезпечити цілісність і несуперечливість даних (табл. 3): Repeatable Read і Serializable для MS SQL Server, Serializable для IBM DB2 та блокування таблиць цілком для PostgreSQL.

Таблиця 3. Блокування СУБД, що використовуються в режимі автоматичних блокувань у транзакції

СУБД

Файлова база даних

MS SQL Server

IBM DB2

PostgreSQL

Вид блокувань

Таблиць

Записів

Записів

Таблиць

Рівень ізоляції транзакцій

Serializable

Repeatable Read або Serializable

Serializable

Read Committed

Часто такий підхід призводить до виникнення «поганих» (надмірних) блокувань і не дозволяє досягти бажаної паралельності роботи користувачів. У клієнт-серверному варіанті блокування даних відбувається на рівні записів, проте може бути заблокована й уся таблиця цілком (наприклад, унаслідок вибору СУБД неоптимального плану виконання запиту ). Тип блокувань, що встановлюються в тому чи іншому випадку, залежить від виду операції, рівня ізоляції транзакцій, що використовується 1С:Підприємством, і визначається внутрішніми механізмами самої СУБД (наприклад, MS SQL Server).

Режим керованих блокувань

У 1С:Підприємстві версії 8.1 реалізовано додатковий режим роботи, що дозволяє використовувати власний менеджер транзакційних блокувань 1С:Підприємства, незалежний від використовуваної СУБД (рис. 16).

Рис. 3.16. Управляемые блокировки в транзакции 1С:Предприятия 8.1: 1С:Предприятие 8.1 I_________I_________I СУБД

Рис. 16. Керовані блокування в транзакції 1С:Підприємства 8.1

Під час роботи в цьому режимі система використовує значно нижчий рівень ізоляції транзакцій для MS SQL Server і IBM DB2 та блокування на рівні записів для PostgreSQL (див. таблицю 3). Це дозволяє досягти вищої паралельності роботи користувачів.

Таблиця 3. Блокування СУБД, що використовуються в режимі керованих блокувань у транзакції

СУБД

Файлова база даних

MS SQL Server

IBM DB2

PostgreSQL

Вид блокувань

Таблиць

Записів

Записів

Записів

Рівень ізоляції транзакцій

Serializable

Read Committed

Read Committed

Read Committed

Однак цей рівень ізоляції транзакцій СУБД вже не може сам по собі забезпечити цілісність і несуперечливість даних у всіх випадках. Тому 1С:Підприємство 8.1 під час модифікації даних методами вбудованої мови (наприклад, метод Записати() в об'єктних даних) встановлює власні керовані блокування в транзакції, які обробляються власним менеджером транзакційних блокувань. Ці блокування також можуть бути встановлені розробником самостійно в тих місцях коду, де потрібно забезпечити незмінність зчитуваних у транзакції даних (спільне блокування) або заборонити читання даних іншими транзакціями (виключне блокування).

Керовані блокування 1С:Підприємства враховують логічну структуру прикладного рішення, тому дозволяють максимально точно блокувати необхідні області даних (на відміну від використовуваних раніше блокувань СУБД, яким не відома логічна структура системи). Таким чином менеджер керованих блокувань дозволяє максимально уникнути виникнення «поганих» (надмірних) блокувань, блокуючи лише дійсно необхідні області даних.

У результаті будь-який запит до даних передусім обробляється власним менеджером транзакційних блокувань 1С:Підприємства 8.1 (див. рис. 16). Якщо на рівні 1С:Підприємства 8.1 конфлікт керованих блокувань не виявляється, то запит передається далі, на виконання СУБД. СУБД також використовує власний механізм блокувань для визначення конфліктних транзакцій, але вже з нижчим рівнем ізоляції транзакцій, ніж у режимі автоматичних блокувань.

Встановлення режиму керування блокуваннями для об'єктів конфігурації

У структурі об'єктів конфігурації існує кілька можливостей для задання режиму керування блокуваннями.
Передусім існує властивість Режим керування блокуванням даних самої конфігурації (рис. 17).

Рис. 3.17. Список значений свойства «Режим управления блокировкой данных» в палитре свойств Конфигурации: si 1

Рис. 17. Список значень властивості «Режим керування блокуванням даних» у палітрі властивостей Конфігурації

Під час вибору значень Автоматичний або Керований режим блокувань під час читання або запису даних будь-якого об'єкта конфігурації визначатиметься саме цим вибраним значенням.

Наприклад, якщо встановлено режим Автоматичний, то під час запису, скажімо, будь-якого елемента довідника використовуватимуться автоматичні блокування, що встановлюються СУБД. Власний менеджер блокувань задіяний не буде. Поведінка системи буде повністю аналогічною поведінці версії 8.0.

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

Якщо ж для властивості конфігурації вибрано режим Автоматичний і керований, то для конкретного об'єкта конфігурації режим блокування визначатиметься значенням властивості Режим керування блокуванням даних самого об'єкта конфігурації (рис. 18).

Рис. 3.18. Список значений свойства «Режим управления блокировкой данных» в палитре свойств объекта конфигурации:

Рис. 18. Список значень властивості «Режим керування блокуванням даних» у палітрі властивостей об'єкта конфігурації

Цей режим призначений для поступового або часткового переведення конфігурації в режим керованих блокувань. Він дозволяє окремим об'єктам метаданих працювати з керованими блокуваннями (наприклад, найбільш «проблемним» документам і регістрам), тоді як інші об'єкти працюють у режимі автоматичних блокувань.

Важливою особливістю роботи в режимі Автоматичний і керований є те, що не в усіх ситуаціях робота з даними об'єкта виконуватиметься саме в тому режимі, який для нього зазначено. Розглянемо цю особливість докладно.

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

У 1С:Підприємстві 8.1 на початку кожної транзакції явно (якщо її розпочато з вбудованої мови) або неявно (якщо її розпочато в результаті дій самої системи) зазначається режим керування блокуваннями в цій транзакції (автоматичний або керований). Таким чином може виявитися, що перша (охоплююча) транзакція відкрита в одному режимі, а друга — в іншому режимі керування блокуваннями. Усього може бути чотири різні поєднання, які наведено в таблиці 3.

Таблиця 3. Поєднання режимів керування блокуваннями в транзакції

Режим наявної транзакції

Режим транзакції, що починається

Результат

Автоматичний

Автоматичний

Транзакція, що починається, буде виконана в автоматичному режимі

Керований

Керований

Транзакція, що починається, буде виконана в керованому режимі

Автоматичний

Керований

Транзакція, що починається, буде виконана в автоматичному режимі

Керований

Автоматичний

Буде викликано виняткову ситуацію

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

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

Розберімо цю особливість на двох прикладах.

Наприклад, запис елемента довідника виконується з вбудованої мови всередині транзакції, відкритої розробником. У цьому разі «першою» (явною) транзакцією буде транзакція, ініційована розробником, а «другою» (неявною) буде транзакція, що відкривається платформою під час виконання методу Записати() об'єкта довідника.

Явна транзакція відкривається розробником за допомогою методу вбудованої мови ПочатиТранзакцію(). На відміну від версії 8.0 цей метод має параметр БлокуванняДаних, який вказує, який режим керування блокуваннями використовуватиметься в цій транзакції. За замовчуванням значення цього параметра дорівнює Автоматичний. Тому, якщо розробник використовує значення цього параметра за замовчуванням, то незалежно від того, який режим встановлено у властивостях записуваного довідника, його запис буде виконано в автоматичному режимі (див. табл. 3, 1 і 3 рядки).

Якщо ж розробник відкриває транзакцію в керованому режимі, то він повинен бути впевнений у тому, що для довідника, який записується в цій транзакції, у властивостях метаданих зазначено керований режим блокувань у транзакції. В іншому разі під час запису елемента довідника буде викликано виняткову ситуацію (див. табл. 3, 2 і 4 рядки).

Розглянемо інший приклад — інтерактивне проведення документа, який виконує рухи за регістром накопичення. У цьому разі «першою» (неявною) транзакцією буде транзакція, що відкривається системою під час запису документа, а «другою» (також неявною) буде транзакція, що відкривається системою під час запису набору записів регістру накопичення.

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

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

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

  • властивість конфігурації Режим керування блокуванням даних необхідно встановити в значення Автоматичний і керований;

  • властивість Режим керування блокуванням даних об'єкта метаданих документа необхідно встановити в значення Керований;

  • у всіх регістрів, за якими цей документ виконує рухи, слід встановити властивість Режим керування блокуванням даних у значення Керований;

  • проаналізувати процедуру проведення документа щодо наявності:

    • явних викликів транзакцій

    • неявних викликів транзакцій, які виконуються системою під час модифікації даних будь-яких об'єктів конфігурації

  • для знайдених явних і неявних викликів транзакцій забезпечити їх виконання в керованому режимі

    • для явних викликів — параметр методу ПочатиТранзакцію();

    • для неявних викликів — властивість Режим керування блокуванням даних модифікованого об'єкта конфігурації;

  • у тілі процедури проведення документа встановити необхідні керовані блокування (про це див. далі).

Встановлення керованих блокувань

Засобами вбудованої мови встановлення керованих блокувань усередині явної або прихованої (неявної) транзакції відбувається за допомогою спеціального об'єкта БлокуванняДаних, опис доступних властивостей і методів якого можна переглянути в синтакс-помічнику в гілці Загальні об'єкти (рис. 19).

Рис. 3.19. Набор свойств и методов объекта «БлокировкаДанных» доступных в Синтакс-помощнике: Синтакс-помощник Содержание Индекс Поиск ф Ф- Ф Ф 45 ф- иапазон /т - П араметры Доступа Web-сервисы Система компоновки данных СравнениеЗначений Г енераторСлучайныхЧисел В- а а а Управление блокировкой данных аивд ? ф: МеТОДЫ рГ ] Добавить Заблокировать Кол а

Рис. 19. Набір властивостей і методів об'єкта «БлокуванняДаних», доступних у Синтакс-помічнику

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

Під час додавання нового елемента блокування для нього необхідно зазначити простір блокувань, який блокуватиме цей елемент. Простори блокувань визначено в платформі 1С:Підприємства 8.1 і вони відповідають структурі прикладних об'єктів конфігурації. Допустимі такі імена просторів блокувань та імена полів просторів блокувань (табл. 9):

Ім'я простору блокуваньПоля простору блокувань
Довідник.<ім'я> Посилання
Документ.<ім'я> Посилання
ПланОбміну.<ім'я> Посилання
ПланРахунків.<ім'я> Посилання
БізнесПроцес.<ім'я> Посилання
Завдання.<ім'я> Посилання
ПланВидівРозрахунку.<ім'я> Посилання
ПланВидівХарактеристик.<ім'я> Посилання
РегістрВідомостей.<ім'я>.НабірЗаписів — тільки для регістру відомостей, підпорядкованого реєстратору Реєстратор
РегістрВідомостей.<ім'я> Період — якщо є;
<ім'я виміру>
РегістрНакопичення.<ім'я>.НабірЗаписів Реєстратор
РегістрНакопичення.<ім'я> Період;
<ім'я виміру>
РегістрБухгалтерії.<ім'я>.НабірЗаписів Реєстратор
РегістрБухгалтерії.<ім'я> Період;
<вид руху> — значення системного переліку ВидРухуБухгалтерії;
Рахунок — обов'язкове поле;
Субконто;
<вид субконто>;
<ім'я виміру>
РегістрРозрахунку.<ім'я>.НабірЗаписів Реєстратор
РегістрРозрахунку.<ім'я> ПеріодРеєстрації;
ПеріодДії;
<ім'я виміру>
Перерахунок.<ім'я>.НабірЗаписів Об'єктПерерахунку
Перерахунок.<ім'я> ВидРозрахунку
Послідовність.<ім'я>.НабірЗаписів Реєстратор
Послідовність.<ім'я> <ім'я виміру>
Константа.<ім'я>

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

Простір блокувань із суфіксом НабірЗаписів використовується в тих випадках, коли необхідно заблокувати самі записи цього об'єкта (наприклад, під час додавання нових записів).
Простір блокувань без суфікса використовується тоді, коли аналізуються деякі дані цього об'єкта (наприклад, залишки регістру) або коли виконуються будь-які операції, що призводять до зміни наявних даних об'єкта (наприклад, відновлення межі послідовності).
Після того, як елемент блокування, що відповідає деякому простору блокувань, додано, слід установити для цього елемента режим блокування (спільне або виключне) та визначити значення полів блокування, щоб зазначити, які саме «записи» буде заблоковано (для кожного простору блокувань у платформі визначено імена полів, значення яких можуть задаватися під час встановлення тих чи інших блокувань).

УВАГА

Слід розуміти, що в цьому випадку не йдеться про реальні записи бази даних. Незважаючи на те, що керовані блокування описуються в термінах об'єктів метаданих та їх полів, ці блокування ніяк не пов'язані з реальною структурою зберігання даних 1С:Підприємства в СУБД. Це лише записи про те, що заблоковано «щось».

Іноді можна провести аналогію між керованими блокуваннями та реальними записами СУБД. Наприклад, для об'єктних даних блокування об'єкта із зазначеним посиланням «відповідатиме» блокуванню всіх записів, що містять зазначене посилання, в усіх таблицях цього об'єкта метаданих (в основній таблиці та в таблицях його табличних частин).

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

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

Умови необхідно ставити саме на ті поля, імена яких наведено у списку імен просторів блокувань. Для кожного простору блокувань кількість встановлюваних умов не обмежена. Умови можуть бути задані або на рівність значення поля будь-якому значенню, або на входження значення поля до зазначеного діапазону.

Існує два способи задання умов на поля просторів блокування:

  • за допомогою явного задання імені поля та його значення;
  • за допомогою зазначення джерела даних, що містить необхідні значення

За явного задання імені поля та його значення необхідно використовувати метод ВстановитиЗначення() об'єкта ЕлементБлокуванняДаних. У цьому випадку ім'я та значення зазначають як параметри методу, наприклад так, як показано в лістингу 1:

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

// Створити об'єкт блокування даних БлокуванняДаних = Новий БлокуванняДаних; // Додати новий елемент блокування, що блокує «щось» у даних регістру накопичення Залишки номенклатури ЕлементБлокування = БлокуванняДаних.Додати("РегістрНакопичення.ЗалишкиНоменклатури"); // Встановити режим блокування — виключний. Інші транзакції, що встановлюють керовані // блокування, не зможуть навіть почати читання цих даних ЕлементБлокування.Режим = РежимБлокуванняДаних.Виключний; // Зазначити, що саме ми блокуємо в даних регістру Залишки номенклатури — усі «записи», у яких // значення виміру Склад дорівнює значенню, що міститься у змінній Склад ЕлементБлокування.ВстановитиЗначення("Склад", Склад);

Для значень типу Дата або Число як значення може бути заданий певний діапазон значень. Діапазон значень передається методу за допомогою об'єкта вбудованої мови — Діапазон. Цей об'єкт дозволяє задати верхню та нижню межі діапазону, причому до діапазону включаються й межі діапазону (лістинг 2).

Лістинг 2. Приклад встановлення умови блокування записів за допомогою задання діапазону

// Створити об'єкт блокування даних БлокуванняДаних = Новий БлокуванняДаних; // Додати новий елемент блокування, що блокує «щось» у даних регістру накопичення Продажі ЕлементБлокування = БлокуванняДаних.Додати("РегістрНакопичення.Продажі"); // Встановити режим блокування — спільний. Ці дані гарантовано не будуть змінені іншими // транзакціями до завершення наявної транзакції ЕлементБлокування.Режим = РежимБлокуванняДаних. Спільний; // Зазначити, що саме ми блокуємо в даних регістру Продажі — усі «записи», у яких // значення виміру Контрагент дорівнює значенню, що міститься у змінній Контрагент ЕлементБлокування.ВстановитиЗначення("Контрагент", Контрагент); // Створити об'єкт Діапазон, що описує інтервал від початку місяця, якому належить зазначена дата, // до зазначеної дати Діапазон = Новий Діапазон(ПочатокМісяця(Дата), Дата); // Зазначити, що саме ми блокуємо в даних регістру Продажі — усі «записи», у яких // значення виміру Контрагент дорівнює значенню, що міститься у змінній Контрагент, // і значення поля Період міститься у зазначеному діапазоні ЕлементБлокування.ВстановитиЗначення("Період", Діапазон);

Під час зазначення джерела даних спочатку необхідно задати властивість ДжерелоДаних об'єкта ЕлементБлокуванняДаних, після чого, використовуючи метод ВикористовуватиЗДжерелаДаних(), налаштувати відповідність полів області блокування даних полям джерела даних (лістинг 3).

Лістинг 3. Приклад встановлення умови блокування записів за допомогою джерела даних

// Створити об'єкт блокування даних БлокуванняДаних = Новий БлокуванняДаних; // Додати новий елемент блокування, що блокує «щось» у даних регістру накопичення Залишки номенклатури ЕлементБлокування = БлокуванняДаних.Додати("РегістрНакопичення.ЗалишкиНоменклатури"); // Встановити режим блокування — виключний. Інші транзакції, що встановлюють керовані // блокування, не зможуть навіть почати читання цих даних ЕлементБлокування.Режим = РежимБлокуванняДаних.Виключний; // Зазначити, що саме ми блокуємо в даних регістру Залишки номенклатури — усі «записи», у яких // значення виміру Склад дорівнює значенню, що міститься у змінній Склад ЕлементБлокування.ВстановитиЗначення("Склад", Склад); // Зазначити джерело даних, яке містить дані для встановлення обмежень на інші поля цього // елемента блокування — у цьому разі таблиця значень СписокНоменклатури ЕлементБлокування.ДжерелоДаних = СписокНоменклатури; // Зазначити, що саме ми блокуємо в даних регістру Залишки номенклатури — усі «записи», у яких // значення виміру Склад дорівнює значенню, що міститься у змінній Склад, // і у яких значення виміру Номенклатура дорівнює будь-якому значенню, що міститься в колонці // Номенклатура зазначеного джерела даних ЕлементБлокування.ВикористовуватиЗДжерелаДаних("Номенклатура", "Номенклатура");

Як джерело даних можна зазначати результат запиту, табличну частину, набір записів або таблицю значень. Під час встановлення відповідності полів іменами полів джерела будуть відповідно імена колонок результату запиту, імена реквізитів табличної частини, імена вимірів або імена колонок таблиці значень. Зауважимо, що об'єкт Діапазон також може бути значенням поля джерела даних.

Для встановлення всіх створених нами блокувань використовується метод об'єкта БлокуванняДаних Заблокувати(). На рисунку 20 показано дію цього методу у разі використання його всередині транзакції та поза нею.

Рис. 3.20. Схема вызова метода «Заблокировать()» объекта «БлокировкаДанных»: Конец трамвзчии Блэ ч вю смят Забое 1 юе ть Б пс иэсе .э на угтамовоем

Рис. 20. Схема виклику методу «Заблокувати()» об'єкта «БлокуванняДаних»

Як випливає з рисунка, якщо цей метод виконується всередині транзакції (явної або неявної), то блокування встановлюються в момент виклику методу. Після завершення транзакції вони будуть зняті автоматично. Якщо ж метод Заблокувати() виконується поза транзакцією, то блокування встановлені не будуть.

Рекомендації щодо модифікації конфігурацій під час переходу до режиму керованих блокувань

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

  • Конвертуємо конфігурацію з версії 8.0 у конфігурацію версії 8.1. Режим керованих блокувань — автоматичний.
  • Якщо в процесі експлуатації інформаційної бази виникають проблеми з паралельністю роботи користувачів — наприклад, часто стали з'являтися повідомлення про перевищення часу очікування блокування або про конфлікти взаємних блокувань, то складаємо список документів, робота з якими призводить до появи вищезазначених проблем.
  • Поступово переводимо конфігурацію в керований режим. Встановлюємо властивість Режим керування блокуванням даних усієї конфігурації загалом у режим Автоматичний і керований.
  • Для зазначених у списку видів документів переводимо властивість Режим керування блокуванням даних у значення Керований. Також у керований режим переводимо всі регістри, за якими ці документи виконують рухи, і всі транзакції (явні та неявні), що відкриваються в процесі проведення документа.
  • Аналізуємо тексти модулів кожного із зазначених видів документів. Нас цікавлять операції читання даних. Причому не всі, а лише ті, де виконується читання деяких даних, на підставі яких потім модифікуються ці ж або інші дані. Очевидно, що зчитувані дані в цьому випадку не повинні бути змінені до завершення транзакції проведення документа, а отже перед читанням їх потрібно заблокувати.
  • Встановлюємо керовані блокування на знайдені нами дані. При цьому спільне блокування встановлюється для того, щоб дані не були змінені іншими транзакціями. Виключне блокування, крім цього, забезпечує заборону не тільки зміни цих даних, а навіть їх читання іншими транзакціями, що встановлюють керовані блокування. Можна сказати, що виключне кероване блокування є засобом боротьби з конфліктами блокувань (deadlock) і може використовуватися аналогічно ключовому слову ДЛЯ ЗМІНИ мови запитів у режимі автоматичних блокувань.

УВАГА

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

Слід пам'ятати, що читання даних іншими транзакціями буде неможливим лише в тому разі, якщо в інших транзакціях встановлюються несумісні керовані блокування. Якщо керовані блокування в інших транзакціях не встановлюються, то читання буде можливим. Це аналогічно тому, як конструкція ДЛЯ ЗМІНИ перешкоджає читанню даних не будь-якими запитами, а лише тими, які теж використовують конструкцію ДЛЯ ЗМІНИ.

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

Як приклад наведемо фрагмент програмного коду з тексту обробника ОбробкаПроведення(), розташованого в модулі документа ВидатковаНакладна (лістинг 4). Під час виконання зазначеного програмного коду система, використовуючи механізм запитів, спочатку читає інформацію з регістру накопичення ЗалишкиНоменклатури, а потім записує до того самого регістру знову сформовані дані. Згідно з нашими рекомендаціями, ми повинні встановити на записи регістру виключне блокування, що забороняє іншим транзакціям, у яких встановлюються керовані блокування, не тільки запис, а й читання записів, що змінюються під час проведення накладної. У цьому випадку виключне блокування потрібне для запобігання можливому конфлікту блокувань (deadlock).

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

Лістинг 4. Приклад встановлення виключного блокування під час проведення документа «ВидатковаНакладна»

БлокуванняДаних = Новий БлокуванняДаних; // Вибрати простір блокувань РегістрНакопичення.ЗалишкиНоменклатури, оскільки ми збираємося аналізувати // залишки регістру ЕлементБлокування = БлокуванняДаних.Додати("РегістрНакопичення.ЗалишкиНоменклатури"); ЕлементБлокування.Режим = РежимБлокуванняДаних.Виключний; // Заблокувати «записи» із зазначеним значенням виміру склад, оскільки в запиті є така умова: // ... І Склад = &Склад) ... ЕлементБлокування.ВстановитиЗначення("Склад", Склад); // Заблокувати «записи» зі значеннями номенклатури з табличної частини, що відповідають умові // ... ВидатковаНакладнаСписокНоменклатури.Номенклатура.Послуга = ХИБНІСТЬ ... // ці дані необхідно отримати запитом до табличної частини ЗапитДжерело = Новий Запит; ЗапитДжерело.Текст = "ВИБРАТИ РІЗНІ | ВидатковаНакладнаСписокНоменклатури.Номенклатура ЯК Номенклатура | Документ.ВидатковаНакладна.СписокНоменклатури ЯК ВидатковаНакладнаСписокНоменклатури |ДЕ | ВидатковаНакладнаСписокНоменклатури.Посилання = &Посилання | І ВидатковаНакладнаСписокНоменклатури.Номенклатура.Послуга = ХИБНІСТЬ"; ЗапитДжерело.ВстановитиПараметр("Посилання", Посилання); ДжерелоНоменклатури = ЗапитДжерело.Виконати(); ЕлементБлокування.ДжерелоДаних = ДжерелоНоменклатури; ЕлементБлокування.ВикористовуватиЗДжерелаДаних("Номенклатура", "Номенклатура"); БлокуванняДаних.Заблокувати(); Запит = Новий Запит; Запит.Текст = "ВИБРАТИ . . . . . . . . . . | ЛІВЕ З'ЄДНАННЯ РегістрНакопичення.ЗалишкиНоменклатури.Залишки(&МомЧасу, | Номенклатура В (ВИБРАТИ РІЗНІ | ВидатковаНакладнаСписокНоменклатури.Номенклатура | З | Документ.ВидатковаНакладна.СписокНоменклатури ЯК | ВидатковаНакладнаСписокНоменклатури | ДЕ | ВидатковаНакладнаСписокНоменклатури.Посилання = &Посилання | І ВидатковаНакладнаСписокНоменклатури.Номенклатура.Послуга = ХИБНІСТЬ) | І Склад = &Склад) ЯК ЗалишкиНоменклатуриЗалишки . . . . . . . . . . |"; . . . . . . . . . . Поки Вибірка.Наступний() Цикл . . . . . . . . . . // регістр ЗалишкиНоменклатури Витрата Рух = Рухи.ЗалишкиНоменклатури.Додати(); Рух.ВидРуху = ВидРухуНакопичення.Витрата; Рух.Період = Дата; Рух.Номенклатура = Вибірка.Номенклатура; Рух.Склад = Склад; Рух.Кількість = Вибірка.Кількість; СумаСписання = ?(Вибірка.КількістьЗалишок = Вибірка.Кількість, Вибірка.СумаЗалишок, Вибірка.СумаЗалишок / Вибірка.КількістьЗалишок * Вибірка.Кількість); Рух.Сума = СумаСписання; КінецьЦиклу; Рухи.ЗалишкиНоменклатури.Записати();

Зверніть увагу, що під час створення джерела даних для встановлення блокувань за номенклатурою ми використали результат запиту до табличної частини. Здавалося б, як джерело даних можна було просто використати табличну частину (ЕлементБлокування.ДжерелоДаних = СписокНоменклатури), але при цьому ми б заблокували зайві дані, адже нас цікавить лише та номенклатура з табличної частини, яка не є послугою (ВидатковаНакладнаСписокНоменклатури.Номенклатура.Послуга = ХИБНІСТЬ). Цей момент якраз добре ілюструє той факт, що до встановлення керованих блокувань потрібно ставитися уважно й не встановлювати «поганих» (надмірних) блокувань.

Тепер розглянемо докладніше питання необхідності встановлення саме виключного керованого блокування.

Якби ми не використовували жодного керованого блокування, то наш запит, що читає дані, почав би виконуватися в будь-якому разі. Після його завершення (ще до завершення транзакції!) СУБД зняла б блокування з прочитаних даних. Це означає, що інша транзакція відразу могла б ці дані змінити (такими є особливості блокувань на рівні ізоляції Read Committed). Тому кероване блокування необхідне для того, щоб гарантувати, що прочитані дані не будуть змінені до завершення нашої транзакції.

Яким чином кероване блокування перешкоджає зміні даних? У результаті виконання методу Заблокувати() у менеджері транзакційних блокувань з'являються записи про ті дані, які ми блокуємо (звісно, якщо вони не конфліктують з наявними блокуваннями) (рис. 21).

Рис. 3.21. Установка управляемых блокировок: Наша транзакция Заблокировать: Номенклатура 1 Номенклатура 2 Номенклатура 3 Менеджер транзакционных блокировок Разделяемая блокировка -Номенклатура 1 Разделяемая блокировка -Номенклатура 2 Разделяемая блокировка -Номенклатура 3

Рис. 21. Встановлення керованих блокувань

За будь-якої спроби модифікації даних інформаційної бази система автоматично намагатиметься встановити виключні керовані блокування для даних, що модифікуються. Таким чином, якщо виявиться, що інша транзакція намагається модифікувати ті дані, які ми вже заблокували, менеджер транзакційних блокувань не дасть їй встановити потрібні блокування, оскільки виключне блокування, яке намагається встановити інша транзакція, несумісне з нашим спільним блокуванням (рис. 22).

Рис. 3.22. Невозможно установить исключительную блокировку на номенклатуру 2: Наша транзакция Менеджер транзакционных блокировок - Разделяемая блокировка - Заблокировать: Номенклатура 1 Номенклатура 1 Разделяемая блокировка - Номенклатура 2 Номенклатура 3 Номенклатура 2 Разделяемая блокировка - г- Номенклатура 3 исполнение кода Искл

Рис. 22. Неможливо встановити виключне блокування на номенклатуру 2

Отже система не зможе змінити дані, заблоковані нами, доти, доки наша транзакція не завершиться і наше блокування не буде знято автоматично після завершення транзакції (рис. 23).

Рис. 3.23. Исполнение кода продолжается после завершения нашей транзакции: Наша транзакция Менеджер транзакционных блокировок Другая транзакция Исключительная блокировка - Л- Номенклатура 4 Заблокировать: Номенклатура 4 Исключительная блокировка - Номенклатура 2 Номенклатура 2 Номенклатура 5 Исключительная блокировка - Номенклату

Рис. 23. Виконання коду продовжується після завершення нашої транзакції

Якби ми використовували лише спільне кероване блокування, то ми могли б отримати конфлікт блокувань (deadlock) з іншою транзакцією.

Наприклад, наша та інша транзакція почали читати залишки з регістру Залишки номенклатури. Списки номенклатури, для яких зчитуються залишки в одній та іншій транзакції, мають однакові елементи. При цьому система в нашій та іншій транзакції встановлює спільне блокування на зчитувані дані. Два спільні блокування на один і той самий ресурс («перетинні» елементи номенклатури) сумісні одне з одним (рис. 24).

Рис. 3.24. Разделяемые блокировки совместимы друг с другом: Наша транзакция Менеджер транзакционных блокировок Другая транзакция Заблокировать: Номенклатура 1 - Разделяемая блокировка -Номенклатура 1 Заблокировать: Номенклатура 4 Номенклатура 2 Номенклатура 3 -+ Разделяемая блокировка -Номенклатура 2 Номенклатура 2

Рис. 24. Спільні блокування сумісні одне з одним

Потім ми завершили читати дані та хочемо записати до цього регістру «нові залишки» для прочитаної номенклатури. Ми не можемо це зробити, оскільки для цього система повинна встановити виключне блокування на записувані дані, але цьому перешкоджає спільне блокування, встановлене на частину цих даних іншою транзакцією. Наша транзакція стає в чергу, очікуючи зняття спільного блокування, встановленого іншою транзакцією (рис. 25).

Рис. 3.25. Наша транзакция не может установить исключительную блокировку на номенклатуру 2: Наша транзакция Менеджер транзакционных блокировок Заблокировать: Номенклатура 1 Номенклатура 2 Номенклатура 3 -+ -+ Разделяемая блокировка -Номенклатура 2 Чтение данных попытка записи данных Разделяемая блокировка -Номенклатура 2 Заблокировать: Номенклату

Рис. 25. Наша транзакція не може встановити виключне блокування на номенклатуру 2

У цей час інша транзакція також завершила читання даних і хоче записати до цього регістру «нові залишки» для прочитаної номенклатури. Вона не може це зробити, оскільки для цього система повинна встановити виключне блокування на записувані дані, але цьому перешкоджає спільне блокування, встановлене на частину цих даних нашою транзакцією. Інша транзакція стає в чергу, очікуючи зняття спільного блокування, встановленого нашою транзакцією (рис. 26).

Рис. 3.26. Конфликт блокировок: другая транзакция также не может установить блокировку на номенклатуру 2: Наша транзакция Заблокировать: Номенклатура 1 Номенклатура 2 Номенклатура 3 Чтение данных попытка записи данных Заблокировать: Номенклатура 1 Номенклатура 2 Номенклатура 3 исполнение кода остановлено, т.к. выполняется ожидание установки блокировки Запись д

Рис. 26. Конфлікт блокувань: інша транзакція також не може встановити блокування на номенклатуру 2

У результаті виникає конфлікт блокувань (deadlock), який може бути вирішений лише примусовим скасуванням однієї з транзакцій.

Тому в цьому випадку необхідне виключне блокування (рис. 27).

Рис. 3.27. Установка исключительных блокировок: Наша транзакция Заблокировать: Номенклатура 1 Номенклатура 2 Номенклатура 3 Чтение данных Менеджер транзакционных блокировок Исключительная блокировка -Номенклатура 1 Исключительная блокировка -Номенклатура 2 Исключительная блокировка -Номенклатура 3

Рис. 27. Встановлення виключних блокувань

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

Рис. 3.28. Другая транзакция не может установить блокировку на номенклатуру 2: Наша транзакция Менеджер транзакционных блокировок Заблокировать: Номенклатура 1 Г -+ Исключительная блокировка -Номенклатура 1 Номенклатура 2 Номенклатура 3 Исключительная блокировка Номенклатура 2 Чтение данных -+ Исключительная блокировка -Номенклатура

Рис. 28. Інша транзакція не може встановити блокування на номенклатуру 2

У результаті виконання коду в іншій транзакції буде зупинено, і система очікуватиме зняття нашого виключного блокування. А наша транзакція зможе завершитися, оскільки інша транзакція не має можливості заблокувати ті записи, які знадобляться нам для модифікації (рис. 29).

Рис. 3.29. Наша транзакция успешно завершается: Наша транзакция Менеджер транзакционных блокировок Другая транзакция Заблокировать: Номенклатура 1 Исключительная блокировка - Заблокировать: Номенклатура 4 Номенклатура 1 Номенклатура 2 Номенклатура 3 Исключительная блокировка - Номенклатура 2 Номенклатур

Рис. 29. Наша транзакція успішно завершується

Записатися телефоном