Розрахований на багато користувачів доступ до даних

4.9.Транзакціі, блокування і розрахований на багато користувачів доступ до даних.

Будь-яка база даних придатна до використання тільки тоді, коли її стан відповідає стану предметної області. Такі стани називають цілісними. Очевидно, що при зміні даних БД повинна переходити від одного цілісного стану до іншого. Однак, в процесі оновлення даних можливі ситуації, коли стан цілісності порушується. наприклад:
  • У банківській системі здійснюється переказ грошових коштів з одного рахунку на інший. Мовою SQL ця операція описується послідовністю двох команд UPDATE. Як бачимо, після виконання першої команди і до завершення другої команди база даних не знаходиться в цілісному стані (шукана сума списана з першого рахунку, але не зарахована на другий). Якщо в цей момент в системі відбудеться збій (наприклад, виключення електроживлення), то цілісний стан БД буде безповоротно втрачено.
  • Цілісність БД може порушуватися і під час обробки однієї команди SQL. Нехай виконується операція збільшення зарплати всіх співробітників фірми на 20%: При цьому СУБД послідовно обробляє всі записи, що підлягають оновленню, тобто існує часовий інтервал, коли частина записів містить нові значення, а частина - старі.

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

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

В СУБД різних постачальників початок транзакції може здаватися явно (наприклад, командою BEGIN TRANSACTION), або матися на увазі неявним (так визначено в стандарті SQL), тобто чергова транзакція відкривається автоматично одразу ж після вдалого або невдалого завершення попередньої. Для завершення транзакції зазвичай використовують команди SQL:
  • COMMIT - успішно завершити транзакцію
  • ROLLBACK - відкотити транзакцію, тобто повернути БД в стан, в якому вона перебувала на момент початку транзакції.
Стандарт SQL визначає, що транзакція починається з першого SQL-оператора, ініційованого користувачем або утримується в прикладній програмі. Усі наступні SQL-оператори складають тіло транзакції. Транзакція завершується одним з можливих способів:
  1. оператор COMMIT означає успішне завершення транзакції, всі зміни, внесення в базу даних робляться постійними
  2. оператор ROLLBACK перериває транзакцію і скасовує всі внесені нею зміни
  3. успішне заверешення програми, яка ініціювала транзакцію, означає успішне завершення транзакції (як використання COMMIT)
  4. помилкове завершення програми перериває транзакцію (як ROLLBACK)
Приклад явно заданої транзакції: Приклад неявно заданої транзакції: На жаль, описаний механізм транзакцій гарантує забезпечення цілісного стану бази даних тільки в тому випадку, коли всі транзакції виконуються послідовно, тобто в кожну одиницю часу активна тільки одна транзакція. Якщо роботу з даними ведуть одночасно кілька користувачів, навряд чи їх влаштує такий спосіб організації обробки запитів, тому що це призведе до збільшення часу реакції системи. У той же час, якщо одночасно виконуються дві транзакції, можуть виникнути такі помилкові ситуації:
  • Брудне читання (Dirty Read) - транзакція Т1 модифікувала якийсь елемент даних. Після цього інша транзакція Т2 прочитала вміст цього елементу даних до завершення транзакції Т1. Якщо Т1 заврешается операцією ROLLBACK. то виходить, що транзакція Т2 прочитала неіснуючі дані.
  • Є повторюваною (розмите) читання (Non-repeatable or Fuzzy Read) - транзакція Т1 прочитала вміст елемента даних. Після цього інша транзакція Т2 модифікувала або видалила цей елемент. Якщо Т1 прочитає вміст цього елементу занова, то вона отримає інше значення або виявить, що елемент даних більше не існує.
  • Фантом (фіктивні елементи) (Phantom) - транзакція Т1 прочитала вміст кількох елементів даних, що задовольняють нікому умові. Після цього Т2 створила елемент даних, що задовольняє цій умові і зафіксувалася. Якщо Т1 повторить читання з тим же умовою, вона отримає інший набір даних.
Як вже було сказано, ні одна з цих ситуацій не може виникнути при послідовному виконанні транзакцій. Звідси виникло поняття Серіалізуемое (здатності до впорядкування) паралельної обробки транзакцій. Тобто чергується (паралельне) виконання заданої множини транзакцій буде вірним, якщо при його виконанні буде отриманий такий же результат, як і при послідовному виконанні тих же транзакцій.

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

Примусове впорядкування транзакцій забезпечується за допомогою механізму блокувань. Суть цього механізму в наступному: якщо для виконання деякої транзакції необхідно, щоб деякий об'єкт бази даних (кортеж, набір кортежів, ставлення, набір відносин.) Не змінився непередбачувано і без відома цієї транзакції, такий об'єкт блокується. Основними видами блокувань є:
  • блокування з взаємним доступом. звана також S-блокуванням (від Shared locks) і блокуванням з читання.
  • монопольна блокування (без взаємного доступу), що також називається X-блокуванням від (eXclusive locks) або блокуванням по запису. Цей режим використовується при операціях зміни, додавання і видалення об'єктів.
При цьому:
  • якщо транзакція накладає на об'єкт X-блокування, то будь-який запит іншої транзакції з блокуванням цього об'єкта буде відкинутий.
  • якщо транзакція накладає на об'єкт S-блокування, то
    • запит з боку іншої транзакції з X-блокувань на цей об'єкт буде відкинутий
    • запит з боку іншої транзакції з S-блокувань цього об'єкта буде прийнятий
Транзакція, що запросила доступ до об'єкта, вже захопленому інший транзакцією в суперечливому режимі, зупиняється до тих пір, поки захоплення цього об'єкта не буде знятий.

Доведено, що серіалізуемость транзакцій (або, інакше, їх ізоляція) забезпечується при використанні двофазного протоколу блокувань (2LP - Two-Phase Locks), згідно з яким всі блокування, вироблені транзакцією, знімаються тільки при її завершенні. Тобто Виконання покрівельних транзакції розбивається на дві фази: (1) - накопичення блокувань, (2) - звільнення блокувань в результаті фіксації або відкоту.

На жаль, застосування механізму блокування призводить до уповільнення обробки транзакцій, оскільки система змушена очікувати поки звільняться дані, захоплені конкуруючої транзакцією. Вирішити цю проблему можна за рахунок зменшення фрагментів даних, що захоплюються транзакцією. Залежно від захоплюваних об'єктів розрізняють кілька рівнів блокування.
  • блокується вся база даних - очевидно, цей варіант неприйнятний, оскільки зводить розрахований на багато користувачів режим роботи до розрахованого на одного користувача
  • блокуються окремі таблиці
  • блокуються сторінки (сторінка - фрагмент таблиці розміром зазвичай 2-4 Кб, одиниця виділення пам'яті для обробки даних системою)
  • блокуються записи
  • блокуються окремі поля
Сучасні СУБД, як правило, можуть здійснювати блокування на рівні записів або сторінок.

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

Схожі статті