Тема: cтворення програмного проекта простої бази даних «Учні» з даними про прізвище, ім'я, успішність, забезпечення виведення даних про учнів за зазначиними критеріями.
Мета: навчити основам роботи з базами даних SQL з використанням мови програмування C++.
Учні повинні знати:
Учні повинні мати уявлення про можливості комплексу C++ i MySQL.
Учні повинні вміти:
Обладнання: комп'ютери зі встановленими ОС Linux Mint/Ubuntu, компілятором g++ і LAMP або хоча б MySQL.
Примітка. Цей урок проводять лише після успішного опанування матеріалом уроків щодо вивчення SQL і виконання усіх його практичних завдань. Операційна система може бути іншою, але тоді вказівки для компіляції і виконання програми будуть відрізнятися від тих, які подано нижче.
Структура уроку
Хід уроку
1. Організаційний момент
Вітання з класом. Перевірка присутності і готовності учнів до уроку.
2. Актуалізація опорних знань
Дати відповідь на питання і порівняти з очікуваним.
3. Вивчення нового матеріалу
Під'єднання бази даних і здійснення запиту мовою SQL мовою C++ здійснюють за допомогою драйвера, бібліотеку з яким встановлюють з сайту dev.mysql.com. Є настанови розробнику (англіською мовою) разом з прикладами
1 i
2.
Щонайменше при ОС Linux Mint 19 потрібно додатково встановити пакунок libmysqlcppconn-dev. Це можна здійснити такими вказівками Терміналу:
sudo apt-get update
sudo apt-get install libmysqlcppconn-dev
Створення програми мовою С++ з використанням MySQL Connector/C++ з динамічно підвантажуваними бібліотеками при ОС Linux Mint/Ubuntu можна здійснити такою вказівкою терміналу:
g++ -Wall -I/usr/include/cppconn demo.cpp -L/usr/lib -lmysqlcppconn -o demo
У цьому випадку буде використано код з файлу demo.cpp і створено виконуваний файл demo, вказаний наприкінці вказівки. Програму можна виконати за допомогою іншої вказівки:
./demo
Розглянемо випадок, коли попередньо виконано такі вказівки MySQL.
SET collation_connection = 'utf8_unicode_ci'; CREATE DATABASE school; ALTER DATABASE school CHARACTER SET utf8 COLLATE utf8_unicode_ci; USE school; SOURCE structure.sql; SOURCE data.sql;
Примітка. Дія всіх вказівок з CHARACTER SET utf8 COLLATE utf8_unicode_ci спрямована на уникнення винятків, породжених конфліктами різних схем упорядкування й порівняння.
У цьому випадку програма мовою C++ може мати такий вигляд
#include <stdlib.h> #include <iostream> #include "mysql_connection.h" #include <cppconn/driver.h> #include <cppconn/exception.h> #include <cppconn/resultset.h> #include <cppconn/statement.h> #include <cppconn/prepared_statement.h> using namespace std; int main(void) { try { sql::Driver *driver; sql::Connection *con; sql::Statement *stmt; sql::ResultSet *res; sql::PreparedStatement *pstmt; // Сполучення з сервером driver = get_driver_instance(); con = driver->connect("tcp://127.0.0.1:3306", // 127.0.0.1 - адреса сервера // 3306 — номер порту; "root", // обліковий запис користувача "!@#123Qwe" // пароль ); // Сполучення з базою даних school con->setSchema("school"); stmt = con->createStatement(); stmt->execute("DROP TABLE IF EXISTS test"); stmt->execute("CREATE TABLE test(i INT, i2 INT)"); delete stmt; pstmt = con->prepareStatement("INSERT INTO test(i,i2) VALUES (?,?)"); for (int i = 1; i < 4; i++) { pstmt->setInt(1, i); pstmt->setInt(2, i*i); pstmt->executeUpdate(); } delete pstmt; pstmt = con->prepareStatement("SELECT * FROM test;"); res = pstmt->executeQuery(); while (res->next()) cout << res->getString(1) << " " << res->getString(2) << endl; delete res; delete pstmt; pstmt = con->prepareStatement("SELECT * FROM pupils WHERE form = '11Б';"); res = pstmt->executeQuery(); while (res->next()) cout << res->getString(1) << " " << res->getString(2) << " " << res->getString(3) << " " << res->getString(4) << endl; delete res; delete pstmt; delete con; } catch (sql::SQLException &e) { cout << "Помилка: виняток SQL у " << __FILE__ << "(" << __FUNCTION__ << ") у рядку " << __LINE__ << endl; cout << "Помилка: " << e.what() << " (MySQL error code: " << e.getErrorCode() << ", SQLState: " << e.getSQLState() << " )" << endl; } return 0; }
з таким виведенням у консоль.
1 1 2 4 3 9 ЛИСЕНКО ДМИТРО 11Б 113 РУДЕНКО ОЛЕГ 11Б 114 САВЧЕНКО ВАЛЕРІЙ 11Б 115 ПЕТРЕНКО ЛЕОНІД 11Б 116 ШУЛЬГА ГАЛИНА 11Б 117 РАДЧЕНКО ТЕТЯНА 11Б 118 КОРОЛЬ НАДІЯ 11Б 119 ОСТАПЕНКО ЛЮДМИЛА 11Б 120
Підготовлений (параметризований) запит
sql::PreparedStatement *pstmt;
використано у поданому вище коді для попередньої компіляції коду SQL, відокремленого від даних.
Переваги підготовлених запитів:
ефективність — їх можна використовувати повторно без повторної компіляції;
безпека — їхнє використання зменшує або усуває можливість атаки шляхом впровадження SQL-коду.
Впровадження SQL-коду (англійською SQL injection) — поширений спосіб злому сайтів і програм, що працюють з базами даних, заснований на впровадженні у запит довільного SQL-коду.
Впровадження SQL може дати можливість зловмиснику виконати довільний запит до бази даних (наприклад, прочитати вміст будь-яких таблиць, видалити, змінити або додати дані), отримати можливість читання та/або запису локальних файлів та виконання довільних вказівок на атакованому сервері.
Підготовлений запит слугує попередньо скомпілюваним шаблоном, у який підставляють значення під час кожного виконання вказівок INSERT, SELECT або UPDATE.
Послідовність використання підготовленого запиту
Підготовка: програма створює шаблон запиту та надсилає його до СУБД. Деякі значення залишають невказаними, що позначають як «?».
Компіляція: СУБД компілює (аналізує, оптимізує та транслює) шаблон запиту та зберігає результат, не виконуючи його.
Виконання: програма надає (прив'язує) значення для параметрів шаблону, а СУБД виконує вказівку (можливо, повертаючи результат). Програма може запросити у СУБД багаторазове виконання оператора з різними значеннями.
Альтернативою підготовленому запиту є виклик SQL безпосередньо з вихідного коду запитом:
sql::Statement *stmt;
у якому поєднано код та дані.
У C++ є декілька ключових слів для роботи з винятками (після тире вказано, для позначення чого використовують відповідне слово):
try — початок блоку коду, який потенційно може привести до помилки;
catch — початок блоку коду, призначеного для перехоплення й опрацювання винятків;
finally — початок додаткового блоку коду, розташованого після останнього блоку catch. Керування зазвичай буде передано у блок finally у будь-якому випадку.
4. Інструктаж з ТБ
5. Закріплення вивченого матеріалу
На початку виконання завдань середовище MySQL/MariaDB повинне бути активним і не містити бази даних school. При виконанні завдань використати демонстраційні розв'язання a, b, c завдань уроку 1 щодо SQL.
Завдання 1. Створити програму мовою C++, яка засобами SQL:
створить базу даних school;
виконає запити створення структури й наповнення таблиць бази даних school згідно з вказівками, записаними у файлах
structure.txt і
data.txt теки проєкту.
Примітка. Вказівка SOURCE є лише вказівкою MySQL, а не SQL, тому нею скористатися буде неможливо. Радимо створити вектор (список) рядків з вказівками SQL;
виведе у консоль назви усіх наявних баз даних;
для усіх наявних таблиць бази даних school виведе у консоль назви цих таблиць і результати запиту щодо їхньої структури у вигляді таблиці такого самого вигляду, як у створеної у середовищі MySQL:
заголовок таблиці вивести такою вказівкою:
cout <<"┌──────────────┬─────────────────────┬──────┬─────┬─────────┬───────┐\n" <<"│ Field │ Type │ Null │ Key │ Default │ Extra │\n" <<"├──────────────┼─────────────────────┼──────┼─────┼─────────┼───────┤\n";
cout<< "│ "+ change(12, rt->getString(1)) + " │ "+ change(19, rt->getString(2)) + " │ "+ change( 4, rt->getString(3)) + " │ "+ change( 3, rt->getString(4)) + " │ "+ change( 7, rt->getString(5)) + " │ "+ change( 5, rt->getString(6)) + " │\n";
у якій використано такі позначення:
cout <<"└──────────────┴─────────────────────┴──────┴─────┴─────────┴───────┘\n";
Порівняти з очікуваними виведенням і кодом.
Примітка. Вимога не використовувати форматоване виведення за допомогою вказівки printf викликано такими обставинами:
printf вимагає використання рядків типу char *, що використовує іншу кількість байтів для збереження одного символу, ніж рядок у кодуванні utf8 (саме таке кодування використовують при ОС Linux);
нехтування попередженням чи використання передбаченого для перекодуваня методу c_str призводять до хибного виведення із зсувом;
у глобальній мережі є рекомендації (програми) для коректного перекодування. Але розуміння їх, не кажучи вже про створення, вимагає багато додаткових зусиль від учня порівняно з виконанням вказівок умови завдання.
Завдання 2. Використовуючи зчитування з файлу попередньо апробованого коду SQL, створити програму мовою C++ для виведення у консоль у вигляді асоціативних масивів таких даних:
всі поля з таблиці pupils про учнів 11Б класу (поле form);
всі поля з таблиці classroom про аудиторії корпусу A (птоле building, латиниця), ємність яких (поле capacity) менше 24 і більше від 16 (2 варіанти);
з таблиці pupils про прізвище (поле sename) та ім'я (поле name) усіх тих записів, у яких прізвище закінчується на 'УК';
з таблиці pupils про прізвище (поле sename) та ім'я (поле name) усіх тих записів, у яких ім'я (поле name) 'Андрій' або 'Григорій';
з таблиці pupils про загальну кількість учнів;
з таблиці tea chers про категорії (поле quality) та кількість учителів цієї категорії;
з таблиці teachers про категорії (поле quality) та кількість учителів цієї категорії, що перевищує 1;
з таблиці marks про прізвище (поле sename) й оцінку (поле mark) за день 2020-09-24 у порядку зростання оцінки;
з таблиці marks про прізвище (поле sename) й оцінку (поле mark) за день 2020-09-24 у порядку спадання оцінки;
з таблиці marks про прізвище (поле sename) й оцінку (поле mark) за день 2020-09-24 у порядку спадання оцінки лише тих, хто посів 4, 5 і 6 місце у цьому списку з підписами стовпчиків 'Прізвище' й 'Оцінка';
з таблиці courses список всіх дисциплін (поле course) і відповідну інформацію про кафедри з таблиці department у режимах;
Незаповнені дані (порожні поля) подавати словом nullекс. Виконати запити й порівняти з очікуваними виведенням і кодом мовою C++.
Примітка. На момент упорядкування тексту упорядник не знашов опису отримання мета-даних результатів запиту, як це втілено для мови Java. Тому у демонстраційному розв'язанні використано виведеня елементів рядка результатів до його завершення з опрацюванням виключення при виході за його межі. Цей піхід використано і в наступних демонстраційних розв'язаннях.
Завдання 3. Використовуючи попередньо апробований код SQL, створити програму мовою C++ для такого:
створити віртуальну таблицю own_view усіх полів усіх записів таблиці marks, у яких оцінка (поле mark) менша ніж 7;
вивести у консоль дані own_view.
Виконати запити й порівняти з очікуваними виведенням і кодом.
Завдання 4. Використовуючи попередньо апробований код SQL, створити програму мовою C++ для такого:
Виконати запити й порівняти з очікуваними виведенням і кодом.
6. Підбиття підсумків уроку
Дати відповідь на питання і порівняти з очікуваним.
Виставлення оцінок.
7. Домашнє завдання
У разі потреби доробити завдання. Вивчити систаксис під'єднання бази даних і здійснення запиту мовою SQL з програми мовою C++. Написати програму мовою C++, яка зчитуватиме з клавіатури й виконуватиме запити SQL до тих пір, поки не буде введено порожній рядок.
Текст упорядкував Олександр Рудик.