Транзакції в mysql і в oracle
Транзакції - одне з фундаментальних понять, що відрізняють базу даних від звичайної файлової системи і від простого набору таблиць.
Транзакція - це група послідовно виконуваних операторів SQL, які або мають бути виконані всі, або не повинен бути виконаний жоден з них. Головне завдання транзакцій - забезпечити цілісність даних у випадках, коли кілька SQL-операторів виконують залежні один від одного зміни даних. Класичний приклад, наведений, напевно, у всіх підручниках по базах даних - переказ грошей з одного рахунку на інший:
UPDATE accounts SET AccSum = AccSum - 1000 WHERE AccNumber = 12345;
UPDATE accounts SET AccSum = AccSum +1000 WHERE AccNumber = 67890;
Що буде, якщо перший оператор виконається, а другий з якоїсь причини - немає (збій сервера, неправильний номер рахунку, переповнення. - хіба мало яка може бути помилка)? Гроші з одного рахунку списані, а на інший не надійшли.
Механізм транзакцій якраз і дозволяє коректно виходити з подібних ситуацій. Об'єднавши ці два оператора UPDATE в одну транзакцію, ми забезпечимо виконання (чи невиконання) їх обох як одного цілого.
Стандарт SQL-92 передбачає, що транзакція в поточній сесії починається неявно при виконанні першого з SQL-операторів, які змінюють дані, а завершена може бути або явно - операторами COMMIT [WORK] або ROLLBACK (COMMIT [WORK] підтверджує транзакцію і фіксує внесені зміни, ROLLBACK транзакцію відкочується і повертає дані в базі до того стану, в якому вони були до початку транзакції), або неявно - при завершенні поточної сесії або при системному збої. На жаль, стандарт SQL-92 не визначає, що повинно робитися за замовчуванням при завершенні поточної сесії - підтвердження транзакції або відкат, і в різних СУБД (і навіть, буває, в різних клієнтів для однієї СУБД) це реалізується по-різному. Тому на дії за умовчанням краще не покладатися і завжди робити COMMIT / ROLLBACK явно.
Транзакції в Oracle
Говорячи про механізм транзакцій в Oracle, можна було б, напевно, обмежитися однією фразою: "Транзакції в Oracle практично повністю відповідають стандарту SQL-92 - дивіться попередній абзац". Додам до цього, мабуть, тільки два моменти.
Транзакції тільки на читання
Такі, втім, також передбачені стандартом SQL-92. Якщо транзакція оголошена як "тільки на читання" (SET TRANSACTION READ ONLY) - це гарантує, що будь-який SELECT, виконаний в рамках цієї транзакції, видасть дані в тому стані, в якому вони були на момент початку транзакції. В межах транзакції "тільки на читання" заборонено будь-яка зміна даних. При цьому транзакція "тільки на читання" не встановлює жодних блокувань даних і не заважає змінювати ці дані іншим сесій.
автономні транзакції
Реалізований в Oracle механізм автономних транзакцій дозволяє створити нову транзакцію в межах поточної. Підтвердження / відкат змін, зроблених в рамках автономної транзакції, проводиться незалежно від батьківської транзакції. Автономні транзакції можуть бути вкладеними, максимальний рівень вкладеності визначається настройками сервера.
Транзакції в MySQL
А ось в MySQL з транзакціями все набагато хитріше.
Почнемо з того, що в MySQL існують таблиці декількох типів: ISAM, HEAP, MyISAM, InnoDB, BDB. З них транзакції можуть підтримувати тільки два останніх: InnoDB і BDB. При цьому "рідними" для MySQL є таблиці типу MyISAM, які транзакції не підтримують. А для того, щоб можна було створювати транзакційні таблиці типів InnoDB і BDB і працювати з ними, сервер MySQL повинен бути відповідним чином налаштований (що далеко не завжди у владі розробників додатків, особливо веб-додатків).
За замовчуванням MySQL працює в режимі autocommit. Це означає, що результати виконання будь-якого SQL-оператора, що змінює дані, будуть відразу фіксуватися (записуватися на диск).
Режим autocommit можна відключити командою SET AUTOCOMMIT = 0. При відключеному режимі autocommit кожну транзакцію треба явно завершувати операторами COMMIT / ROLLBACK.
Для одноразового переходу в транзакційний режим можна використовувати команду START TRANSACTION (в MySQL починаючи з версії 4.0.11) або BEGIN [WORK]:
START TRANSACTION;
UPDATE accounts SET AccSum = AccSum - 1000 WHERE AccNumber = 12345;
UPDATE accounts SET AccSum = AccSum +1000 WHERE AccNumber = 67890;
COMMIT;
Зверніть увагу на серйозний підводний камінь. Якщо в транзакції беруть участь таблиці різних типів (транзакційні і нетранзакціонние), то вести вони себе будуть зовсім по-різному. Зміни в нетранзакціонние таблиці будуть вноситися негайно, незважаючи на відключений режим autocommit, і їх неможливо буде відкотити за допомогою оператора ROLLBACK! А якщо ROLLBACK все ж буде виконаний - зміни, внесені в транзакційні таблиці, відкотяться, а в нетранзакціонние - збережуться. До чого це може призвести - думаю, розжовувати не треба.