Последние записи
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
- Сравнение языков на массивах. Часть 2
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
12th
Июл
Работа с MySQL в C++
Posted by Chas under Статьи, Топик-обзор
Небольшая статья по взаимодействию с СУБД MySQL из программы на C++
автор статьи: psycho-coder
Тема на форуме
Немного теории
Код:
MYSQL mysql; // Дескриптор соединения. Структура, содержащая HANDLE для одного подключения к серверу.
MYSQL_RES *res; // Дескриптор результирующей таблицы
MYSQL_ROW row; // Массив полей текущей строки
MYSQL_FIELD *field; // Структура, которая содержит всю информацию, касающуюся отдельного поля таблицы
Функиции которые нам понабодятся:
Функция инициализации
MYSQL *mysql_init(MYSQL *mysql);
Где соответственно host — компьютер, на котором запущена СУБД MySQL, user — имя юзера для подключения, passwd — пароль, db — название предполагаемой для использования базы данных, port — порт, unix_socket — сокет или pipe-канал, который необходимо использовать.
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned int client_flag)
client_ flag может принимать несколько значений:
CLIENT_COMPRESS — используется сжатие.
CLIENT_FOUND_ROWS — возвращать число найденных строк.
CLIENT_IGNORE_SPACE — делает все имена функций зарезервированными словами.
CLIENT_INTERACTIVE — разрешает interactive_timeout секунд бездействовать (вместо wait_timeout) перед закрытием подключения.
CLIENT_NO_SCHEMA — запрещает синтаксис вида “db_name.tbl_name.col_name” (имя_базы_данных.имя_таблицы.имя_ко лонки). Используется для ODBC.
CLIENT_ODBC — устанавливает то, что это клиент ODBC.
CLIENT_SSL — используется защищенный протокол SSL.
Мы флагами пользоваться не будем.
Функция выполняющая запрос
int mysql_query(MYSQL *mysql, const char *query);
Функция возвращяющая строку с описанием ошибки
Код:
char *mysql_error(MYSQL *mysql);
функция, которая получает все строки результата запроса и хранит их в буфере-клиенте
MYSQL_RES * mysql_store_result(MYSQL *mysql);
Получает количество строк в результате запроса
my_ulonglong mysql_num_rows(MYSQL_RES *res);
Получает количество полей (столбцов) в результате запроса
unsigned int mysql_num_fields(MYSQL_RES *res);
Заполняет массив полей для текущей строки
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
Заполняет структуру для текущего поля (fieldnr)
MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res, unsigned int fieldnr);
Начальная “настройка”
Для работы в Builder необходимо конвертировать libmysql.lib.
Для этого, нужно открыть консоль и набрать там это
C:\>”C:\Program Files\Borland\CBuilder6\Bin\coff2omf.exe”
-lib:st “C:\Program Files\Borland\CBuilder6\Lib\libmysql.lib”
“C:\Program Files\Borland\CBuilder6\Lib\libmysql_.lib”
Здесь “C:\Program Files\Borland\CBuilder6\Lib\libmysq l.lib” оригинальная библиотека,
а “C:\Program Files\Borland\CBuilder6\Lib\libmysq l_.lib” конвертированная
У каждого пути будут свои.
Также в папке с программой (или в “C:\Program Files\Borland\CBuilder6\Lib\”) должны быть libmysql_.lib, а для VS libmysql.dll.
Заголовочные файлы можно бросить в папку с программой или в “C:\Program Files\Borland\CBuilder6\Include\”.
Для VS “C:\Program Files\Microsoft Visual Studio Х.0\VC\include”. Где Х – версия VS.
В среде MS VC++ можно использовать библиотеку без конвертации, т.е. libmysql.lib.
Все заголовочные файлы могут быть в папке с программой, но тогда нужно подключать их локально.
Есть замечания для VC++ WinForms.
Так как типы String^ и char[] несовместимы, то для конвертирования из String^ в char[] можно использовать следующие функции (взято из MySQL++):
private: String^ ToUCS2(const char* utf8)
{
try
{
return gcnew String(utf8, 0, strlen(utf8), System::Text::Encoding::Default);
}
catch(…)
{
return “”;
}
}
private: Void ToUTF8(char* pcOut, int nOutLen, String^ sIn)
{
try
{
array^ bytes = System::Text::Encoding::Default->GetBytes(sIn);
nOutLen = Math::Min(nOutLen – 1, bytes->Length);
System::Runtime::InteropServices::Marshal::Copy(bytes, 0, IntPtr(pcOut), nOutLen);
pcOut[nOutLen] = ”;
}
catch (…)
{
pcOut[nOutLen] = ”;
}
}
Пример использования
const int buf = 512;
char host[buf];
ToUTF8(host, buf, hostText->Text); // Перевод из String^ в char[]
String ^tmp = ToUCS2(mysql_error(&mysql)); // Перевод из char* в String^
Вот все необходимое для работы:
libmysql_lib.rar 2.5 кб
libmysql.lib.rar 5.1 кб
LibMySQL.dll.rar 447 кб
include.rar 73.7 кб
Вывод в консоль
Вывод таблиц в консоли. Интерфейс правда не супер, но для практики думаю хватит.
В коде есть комментарии. Если будут вопросы задавайте здесь
#define __LCC__ // Объявляем директиву без которой программа не может работать. Можно конечно поключить windows.h, но это будет не красиво
#pragma comment(lib, “libmysql_.lib”) // подключаем библиотеку
#include // Заголовочный файл с описание функций
#include
#include
void mysql(const char query[])
{
MYSQL mysql; // Дескриптор соединения
MYSQL_ROW row; // Массив полей текущей строки
MYSQL_RES *res; // Дескриптор результирующей таблицы
char host[] = “localhost”; // хост
char user[] = “admin”; // пользователь
char passwd[] = “admin”; // пароль
char db[] = “library”; // название базы данных
int port = 0; // порт. Если порт у сервера MySQL не по умолчанию (3306), то нужно указывать конкретный номер порта
mysql_init(&mysql); // Инициализация
mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0); // соединение
if (mysql_query(&mysql, query) > 0) // запорс. Если ошибок нет, то продолжаем работу
{
// Если была ошибка, …
printf(”%s”, mysql_error(&mysql)); // … вывдем ее
return; // и завершим работу
}
res = mysql_store_result(&mysql); // Берем результат,
int num_fields = mysql_num_fields(res); // количество полей
int num_rows = mysql_num_rows(res); // и количество строк.
for (int i = 0; i < num_fields; i++) // Выводим названия полей
{
field = mysql_fetch_field_direct(res, i); // Получение названия текущего поля
printf(”| %s |”, field->name);
}
printf(”\n”);
for (int i = 0; i < num_rows; i++) // Вывод таблицы
{
row = mysql_fetch_row(res); // получаем строку
for (int l = 0; l < num_fields; l++)
printf("| %s |", row[l]); // Выводим поля
printf(”\n”);
}
printf(”Count records = %d”, num_rows); // Вывод информации о количестве записей
mysql_free_result(res); // Очищаем результаты
mysql_close(&mysql); // Закрываем соединение
}
int main()
{
mysql(”SELECT * FROM t_mid_author”); // Запрос
getch(); // Ожидаем нажатие клавиши
return 0;
}
Графический интерфейс
Очередная статья по взаимодействию с СУБД MySQL из программы на С++
Мутим простейший интерфейс
Кидаем на форму:
TLabel (5 шт.). В свойство Caption пишем хост, порт и т.д.
TEdit (5 шт.). Названия TEdit’ов: hostText, userText, passText, dbText и portText.
TButton (2 шт.). В свойства Caption пишем “Пошел!” и “Закрыть”.
TMemo (1 шт.)
TStringGrid (1 шт.)
Подключаем заголовочные файлы, библиотеку и объявим одну константу
#define __LCC__
#include
#pragma comment(lib, “libmysql_.lib”) // Для Builder 6. Подробней см. в первой статье
#pragma comment(lib, “libmysql.lib”) // Для MS VC++
// Для других сред программирования не пробовал
const int buf = 512;
Обработчик кнопки “Закрыть” думаю понятен
А в обработчик копки “Пошел!” пишем следующее
/* Проверим что все данные были введены? в.ч. и сам запос (Memo1) */
if (hostText->Text.IsEmpty() || userText->Text.IsEmpty() ||
passText->Text.IsEmpty() || dbText->Text.IsEmpty() ||
portText->Text.IsEmpty() || Memo1->Text.IsEmpty())
{
MessageBox(this->Handle, “Не все поля заполнены!”, “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
// Тут Вам все должно быть знакомо
MYSQL mysql;
MYSQL_ROW row;
MYSQL_RES *res;
MYSQL_FIELD *field;
/* Объявляем массивы для работы */
char host[buf];
char user[buf];
char passwd[buf];
char db[buf];
char query[buf];
int port = portText->Text.ToInt();
int num_fields = 0;
int num_rows = 0;
/* Инициализируем имя хоста, пользователя, пароль и БД */
strcpy(host, hostText->Text.c_str());
strcpy(user, userText->Text.c_str());
strcpy(db, dbText->Text.c_str());
strcpy(passwd, passText->Text.c_str());
strcpy(query, Memo1->Text.c_str()); //*/
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0))
{ /* Пробуем подключиться, если кдето ошибка то сообщим об этом */
MessageBox(this->Handle, mysql_error(&mysql), “Error!”,
MB_OK | MB_ICONERROR);
return;
}
if (mysql_query(&mysql, query) > 0)
{ /* Пробуе выполнить запрос, если запрос не верен то сообщаем об ошибке,
Выведем ее и выходим
*/
MessageBox(this->Handle, mysql_error(&mysql), “Error!”,
MB_OK | MB_ICONERROR);
return;
}
// Получаем результат
res = mysql_store_result(&mysql);
/* Устанавливаем кол-во строк в таблице и сохраняем кол-во строк */
StringGrid1->RowCount = num_rows = mysql_num_rows(res);
/* Устанавливаем кол-во полей и сохраняем это кол-во столбцов */
StringGrid1->ColCount = num_fields = mysql_num_fields(res);
StringGrid1->FixedRows = 1; // Фиксируем первую строку.
for (int i = 0; i < num_fields; i++) // Выводим названия полей
{
field = mysql_fetch_field_direct(res, i);
StringGrid1->Cells[0] = field->name; // В первую строку, которую мы зафиксировали
}
for (int i = 1; i < num_rows; i++) // Вывод результата запроса
{
row = mysql_fetch_row(res); // Получаем строку
for (int l = 0; l Cells[l] = row[l]; // Выводим строку по ячейкам
}
mysql_free_result(res); // Освобождаем память
mysql_close(&mysql); // Закрываем соединение
Вот и все. пишем запрос и “Пошел!”.
Графический интерфейс. Специальный проект
Теперь напишем “специальный” клиент для базы данных Библиотека
Для начала создадим базу банных
# create.sql
# Создаем базу данных
CREATE database lib;
# Переключаемся на нее
use lib;
# Добавляем пользователя admin с паролем admin и связываем его с базой library
GRANT ALL ON lib.* TO ‘admin’@’%’ IDENTIFIED BY ‘admin’;
# Создаем таблицу книги
CREATE TABLE IF NOT EXISTS t_books
(
ID INT(6) UNSIGNED NOT NULL AUTO_INCREMENT,
Title CHAR(150) NOT NULL,
FIO CHAR(150) NOT NULL,
PRIMARY KEY(ID),
KEY(Title)
);
Интерфейс формы у меня получился такой.
Компоненты:
TLabel и TEdit . по 5 штук, как из предыдущей статьи
ListBox – 1 шт список книг
GroupBox – 1 шт. В нем 2 TLabel и 2 TEdit, название книги и автор
TButton – 5 шт. Их желательно обозвать как у меня (Удалить, Изменить, Добавить, Подключиться, Закрыть).
BitBtn – 1 шт кнопка обновление данных.
TTimer – 1 шт проверка содинения.
Все подробности на скрине.
Объявляем необходимые переменные и подключаем все что нужно…
#define __LCC__
#pragma comment(lib, “libmysql_.lib”)
#include
const int buf = 512; // Буфер
bool connected = false; // Есть соединение или нет
int *arrIDs = NULL; // Массив идентификаторов
int ID = 0; // Идентификатор текущей книги
MYSQL mysql; // Дескриптор соединения
MYSQL_RES *res; // Структура результатов
MYSQL_ROW row; // Массив строк результата
/* Объявляем массивы для работы */
char host[buf];
char user[buf];
char passwd[buf];
char db[buf];
int port = 0;
Настройки таймера:
Enabled := false; // Выключен
Interval := 5000; // 5 секунд
Код обработчика таймера:
if (mysql_ping(&mysql) > 0) // Если соединение разорвано…
{
connected = false; // ставим флаг дисконнекта
if (arrIDs) delete []arrIDs; // Очищаем массив
Timer1->Enabled = false; // … выключаем таймер
MessageBox(this->Handle, “Соединение с сервером потеряно”, “Ошибка!”,
MB_OK | MB_ICONERROR); // Выведем сообщение лоб этом
Button5->Click(); // Запустим повторное соединение
}
Далее обработчики кнопок
Код кнопки “Подключиться”
// Подключение
if (connected) return; // Если уже соединены, то выходим.
/* Проверим, что все данные были введены */
if (hostText->Text.IsEmpty() || userText->Text.IsEmpty() ||
passText->Text.IsEmpty() || dbText->Text.IsEmpty() ||
portText->Text.IsEmpty())
{
MessageBox(this->Handle, “Не все поля заполнены!”, “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
/* Инициализируем имя хоста, пользователя, пароль, порт и БД */
strcpy(host, hostText->Text.c_str());
strcpy(user, userText->Text.c_str());
strcpy(db, dbText->Text.c_str());
strcpy(passwd, passText->Text.c_str());
port = portText->Text.ToInt();
mysql_init(&mysql); // Инициализация дескриптора
if (!mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0))
{ /* Пробуем подключиться, если кде-то ошибка, то сообщим об этом */
MessageBox(this->Handle, mysql_error(&mysql), “Error!”,
MB_OK | MB_ICONERROR);
return;
}
connected = true; // Соединены
Timer1->Enabled = true; // Порверка соединения каждые 5 сек.
BitBtn1->Click(); // Обновить список
Код кнопки “Обновить” (BitBtn1)
// Обновление списка книг
if (!connected) return; // Если соединения нет, то выходим
/* Так как, мы знаем что нам нужно, то и запрос будет статическим.
Получим названия всех книг и идентификаторов, потом заполним ими ListBox
Сортируем в порядке возрастания по названию книги */
if (mysql_query(&mysql, “SELECT ID, Title FROM t_books ORDER BY Title”) > 0)
{ // Проверка на ошибки
MessageBox(this->Handle, mysql_error(&mysql), “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
ListBox1->Clear(); // Очистка списка.
if (arrIDs) delete []arrIDs; // Очистка массива
// Заполняем структуру
res = mysql_store_result(&mysql);
// Получаем количество записей
int count = mysql_num_rows(res); // Получаем количество строк
arrIDs = new int[count]; // Инициализируем массив
for (int i = 0; i < count; i++)
{
// Полчаем строку
row = mysql_fetch_row(res);
// Заполняем массив
arrIDs = StrToInt(row[0]);
// Добавляем в ListBox название книги
ListBox1->Items->Add(row[1]);
}
mysql_free_result(res); // Освобождаем ресурсы
Графический интерфейс. Специальный проект. Продолжение
Код кнопки “Добавить”
// Добавление книг
// Если соединения нет или поля ввода пустые, то выходим
if (!connected && (bookText->Text.IsEmpty() || authorText->Text.IsEmpty()))
return;
// Формируем запрос на добавление книги
AnsiString tmp = “INSERT INTO t_books (ID, Title, FIO) VALUES (NULL,\
‘” + bookText->Text + “‘, ‘” + authorText->Text + “‘)”;
char query[buf]; // Переменная дла запроса
strcpy(query, tmp.c_str()); // Ковертируем в нужный формат.
// Запрос. Если ошибки есть, то выводим их и выходим из функции
if (mysql_query(&mysql, query) > 0)
{
MessageBox(this->Handle, mysql_error(&mysql), “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
// Вывод сообщения о том, что все хорошо.
MessageBox(this->Handle, “Книга добавлена!”, “”, MB_OK | MB_ICONINFORMATION);
bookText->Clear();
authorText->Clear();
BitBtn1->Click(); // Обновим данные
Код кнопки “Изменить”
// Изменение книг
// Если соединения нет и книга не выбрана, то выходим
if (!connected && ID < 1) return;
AnsiString tmp = “UPDATE t_books SET Title = ‘” + bookText->Text +”‘,\
FIO = ‘” + authorText->Text + “‘ WHERE ID = ” + IntToStr(ID);
char query[buf];
strcpy(query, tmp.c_str());
if (mysql_query(&mysql, query) > 0)
{
MessageBox(this->Handle, mysql_error(&mysql), “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
MessageBox(this->Handle, “Информация о книге обновлена”, “”,
MB_OK | MB_ICONINFORMATION);
Код кнопки “Удалить”
// Удаление книг
// Если соединения нет и нет выделенной книги для удаления, то выходим
if (!connected && ID < 1) return;
// Подтверждение удаления
if (MessageBox(this->Handle, “Удалить?”, “Удаление”,
MB_YESNO | MB_ICONQUESTION) != 6) return;
// Формируем запрос на удаление
AnsiString tmp = “DELETE FROM t_books WHERE ID = ” + IntToStr(ID);
char query[buf];
// Приводим его
strcpy(query, tmp.c_str());
// Выполняем.
if (mysql_query(&mysql, query) > 0)
{
MessageBox(this->Handle, mysql_error(&mysql), “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
MessageBox(this->Handle, “Книга удалена”, “”, MB_OK | MB_ICONINFORMATION);
BitBtn1->Click();
Выбор книги из ListBox будет производится по двойному щелчку
// Выбор книги
// Если соединения нет, то выходим
if (!connected) return;
// Тут надеюсь все понятно. Если нет, смотрите “Обновление списка”
AnsiString tmp = “SELECT FIO FROM t_books WHERE ID = ”
+ IntToStr(arrIDs[ListBox1->ItemIndex]);
char query[buf];
strcpy(query, tmp.c_str());
if (mysql_query(&mysql, query) > 0)
{
MessageBox(this->Handle, mysql_error(&mysql), “Ошибка!”,
MB_OK | MB_ICONERROR);
return;
}
// Получаем результаты
res = mysql_store_result(&mysql);
row = mysql_fetch_row(res);
// Получаем идентификатор книги
ID = arrIDs[ListBox1->ItemIndex];
// Выводим название книги
bookText->Text = ListBox1->Items->Strings[ListBox1->ItemIndex];
// Выводим автора
authorText->Text = row[0];
mysql_free_result(res);
И, по закрытию программы написать
// Закрытие программы
// Если соединены, то разрываем соединение.
if (connected)
{
mysql_close(&mysql);
if (arrIDs) delete []arrIDs;
}
все исходники статьи и скрипт sql
Вся статья (сделана под форум). В аттаче.
mysql.txt
Обсудить на форуме — Работа с MySQL в C++
Похожие статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)