Транзакції в mysql 2
1. Постановка завдання
Для сьогоднішнього уроку я підготував ось таку HTML сторінку:
Фреймворк YII2. Швидка розробка з сучасним PHP фреймворком
Дізнайся тонкощі сучасної веб-розробки за допомогою фреймворка YII2
Як Ви бачите - це всього одна сторінка інтернет магазину. А саме сторінка відображення товарів з каталогу - центральний блок, і кошик, в якій вже міститься кілька товарів.
Насправді - це статична сторінка і звичайно сам механізм додавання товарів в корзину не працює, так як тема уроку зовсім інша. Але тим не менше три товара, які відображені в кошику - збережені в сесії і якщо натиснути на посилання "Оформити замовлення", то замовлення на покупку цих товарів буде оформлений. Якраз на прикладі оформлення замовлення товару ми з Вами побачимо всі переваги використання транзакцій при роботі з базою даних. Але перед цим, давайте розглянемо, як працює цей тестовий сайт.
Отже, весь контент даного тестового сайту, міститься в базі даних, а саме в таблиці magazine. Також в базі містяться ще три таблиці - otpravleno, user_cash, zakazi.
Таблиця otpravleno - використовується для оплачених і як би відправлених замовлень (знову ж віртуально), таблиця user_cash - зберігає віртуальні кошти користувача, як ніби у нас на сайті діють віртуальні кошти, якими можна оплачувати товар (це потрібно просто для прикладу) і нарешті, таблиця zakazi -все замовлення оформлені на сайті.
Тобто процес оформлення замовлення зводиться до послідовного виконання декількох SQL запитів до бази даних: додавання в таблицю zakazi - даних про оформленому замовленні, зняття грошових коштів у користувача за куплені товари (тобто зміна даних в таблиці user_cash), додавання в таблицю otpravleno даних про оплачених товарах і нарешті зміна кількості товарів на складі (тобто зменшення кількості товарів в таблиці magazine, що були куплені).
Звичайно, в реальному магазині такі запити не виконуються, але для цього уроку такий приклад буде якраз до речі.
Тепер давайте коротко розглянемо вихідний код даного сайту.
Отже, основа логіки сайту - це файл functions.php, в якому описані всі необхідні для роботи сайту функції.
Коротко про кожну функції:
connect_db - функція яка виконує підключення до бази даних.
get_goods - функція яка отримує з бази даних, дані про товари і повертає їх у вигляді масиву.
get_cart - функція яка зберігає в сесії три перших товару з бази даних (буквально для прикладу, що б було з чого оформляти замовлення).
zakaz - функція оформлення замовлення. Ця функція послідовно виконує запити до бази даних про яких я говорив вище.
Також частиною вихідного коду, є файли index.php і cart.php, але їх код я зараз наводити не буду, так як він дуже простий. Дані файли Ви зможете знайти в исходниках до даного уроку.
З усього вище сказаного випливає - для того що б оформити замовлення необхідно що б виконалися без помилок SQL запити до функцій zakaz. Але уявіть собі таку ситуацію: наприклад користувач вибрав товари для покупки, натиснув на кнопку Оформити замовлення і починає виконуватися функція zakaz, тобто виконується перший запит - зберігаємо дані про замовлення, далі другий - списуємо кошти з рахунку користувача (змінюємо дані в таблиці user_cash), але при виконанні третього запиту виникає помилка. Що при цьому виходить - замовлення оформлене, гроші у користувача зняті з рахунку, але товар не був переданий на відправку. Погодьтеся досить неприємна ситуація. Тому давайте знайдемо рішення даної проблеми.
2. Що таке транзакції?
Транзакції - це послідовність різних SQL запитів, що виконуються як одне ціле, і не переривається іншими клієнтами. Тобто, коли виконуються запити транзакції, доступ до записів ніхто отримати не може.
Завдяки транзакціях ми можемо, як би створити групу запитів, які гарантовано будуть виконані без помилок. Якщо ж в ході виконання транзакції відбувається збій, або виникають помилки, то результати виконання всіх запитів до місця виникнення помилки скасовуються. Тим самим, стан бази даних, повертається у вихідне - до моменту виконання запитів транзакції.
Наприклад, якщо Вам потрібно виконати поспіль 100 SQL запитів, і Ви, при цьому використовуєте транзакції, то, якщо в ході виконання цих запитів хоча б один з них виконається з помилкою, або не виконається взагалі - стан бази даних повернеться до свого початкового стану - на момент виконання даних запитів. І тільки після успішного виконання останнього 100го запиту всі зміни вступлять в силу.
Суть транзакцій полягає в тому, що за замовчуванням вимкнено підтвердження виконання запитів, тобто після виконання запиту база даних буде чекати спеціальне повідомлення про підтвердження успішного виконання запиту - повідомлення commit. Як тільки буде отримано дане повідомлення - зміни вступлять в силу. Якщо ж відправити в базу даних повідомлення rollback - відбудеться відкат всіх змін (скасування) в базі даних на момент початку виконання транзакції.
Транзакції виконуються шляхом ведення журналу всіх змін, що вносяться до бази даних при роботі кожної транзакції. Коли виконується відкат змін, база даних звертається до журналу і скасовує всі виконані запити для поточної транзакції.
3. Застосування транзакцій до тестового скрипту
Отже, для того що б почати працювати з транзакціями, насамперед необхідно скасувати автоматичне підтвердження виконання SQL запитів в базі даних. Для цього використовуємо функцію:
Хочу зазначити, що для роботи з базою даних я використовую розширення мови php mysqli, так як розширення mysql вже істотно застаріло, і не містить в собі, функцій для роботи з транзакціями. Ще одне важливе зауваження: для роботи з транзакціями необхідно використовувати таблиці в базі даних типу InnoDB, тип MyISAM - транзакції не підтримує.
Далі, після кожного запиту необхідно виконати перевірку - чи успішно виконаний даний запит, якщо виникла помилка, то відразу ж необхідно відправити базі даних повідомлення про відкат всіх змін. Для цього необхідно використовувати функцію:
Якщо ж Ви впевнені, що всі запити успішно виконані - значить можна відправляти повідомлення commit - підтвердження виконання транзакції:
Тепер давайте змінимо функцію zakaz таким чином, що б відправка і виконання запитів здійснювалося за допомогою транзакцій.
Як Ви бачите, виконуємо всі, про що я говорив вище, тобто відключаємо автоподтвержденіе виконуваних запитів (mysqli_autocommit ($ db, FALSE)), потім після кожного запиту виконуємо перевірку наявності помилок, якщо ж є помилки негайно виконуємо відкат всіх змін (mysqli_rollback ( $ db)). Тут також важливо виконувати вихід їх функції, в нашому випадку простий повернення (return), так як якщо запит виконаний з помилкою, немає сенсу продовжувати виконання коду функції zakaz. Якщо ж все запити виконані успішно, підтверджуємо транзакцію (mysqli_commit ($ db);).
Перед тим як перевірити, я пропоную функцію zakaz описати іншим способом, а саме, використовувати блоки try-catch для перевірки виконаних запитів. Нагадаю, що блоки try-catch - реалізують механізм обробки виключень мови PHP.
Дивіться, весь код циклу ми укладаємо в блок try, а в кожному блоці if () ми з Вами генеруємо виняток. Тобто коли виконається, хоча б один блок if, відразу ж буде створено виняток, і скрипт миттєво буде перенаправлений в блок catch, який в свою чергу і виконає відкат всіх змін. Якщо ж все нормально, і жоден з блоків if не виконається, значить потрібно просто підтвердити транзакцію, що ми власне і робимо.
Тепер давайте навмисно допустимо помилку в одному із запитів і виконаємо наш скрипт. Як Ви бачите, якщо при виконанні запиту виникає помилка, то відразу ж відбувається відкат всіх змін і відновлення бази даних до свого початкового стану. Тобто все успішно працює. Тому якщо Вам необхідно виконати кілька дуже відповідальних запитів до бази даних, завжди застосовуйте транзакції, що б уникнути неприємних наслідків від з'являються помилок.
На цьому я даний урок завершую, всього Вам доброго і до зустрічі в наступних уроках.
Найсвіжіші новини IT і веб-розробки на нашому Telegram-каналі