Страница 1 из 1

Подключение к базе данных MySQL (библиотека mariadb.hpp)

Добавлено: 26 май 2025, 09:41
ya
http://www.w3schools.com/mysql/

Необходимые пакеты к установке

Код: Выделить всё

sudo apt install libmariadb-dev libmariadb-dev-compat
Конфигурация:
config.hpp

Код: Выделить всё

    struct sqlDB
    {
        std::string sql_host = "localhost";
        std::string sql_login = "";
        std::string sql_passwd = "";
        std::string sql_db = "";
    };
Библиотека:
mariadb.hpp

Код: Выделить всё

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
#include <mysql/mysql.h>

class Database {
public:
    static Database& getInstance() {
        static Database instance; // Инициализация одиночки
        return instance;
    }

bool connect(const char* host, const char* user, const char* password, const char* db_name, int max_attempts = 5, int delay_seconds = 2) {
    int attempts = 0;
    while (attempts < max_attempts) {
        conn = mysql_init(nullptr);
        if (conn == nullptr) {
            std::cerr << "mysql_init() failed" << std::endl;
            return false;
        }

        if (mysql_real_connect(conn, host, user, password, db_name, 0, nullptr, 0) != nullptr) {
            return true; // Успешное подключение
        }

        std::cerr << "mysql_real_connect() failed: " << mysql_error(conn) << std::endl;
        mysql_close(conn);
        conn = nullptr;

        attempts++;
        std::cerr << "Попытка подключения (" << attempts << "/" << max_attempts << ") через " << delay_seconds << " секунд..." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(delay_seconds)); // Задержка перед повторной попыткой
    }

    return false; // Все попытки подключения завершились неудачно
}

    void executeQuery(const char* query) {
        if (mysql_query(conn, query)) {
            std::cerr << "QUERY FAILED: " << mysql_error(conn) << std::endl;
        } else {
            MYSQL_RES *res = mysql_store_result(conn);
            if (res) {
                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res))) {
                    for (unsigned int i = 0; i < mysql_num_fields(res); i++) {
                        std::cout << (row[i] ? row[i] : "NULL") << "\t";
                    }
                    std::cout << std::endl;
                }
                mysql_free_result(res);
            }
        }
    }


    
void executeQuery_select(const char* query, std::unordered_map<std::string, std::vector<std::string>>& data) {
    if (mysql_query(conn, query)) {
        std::cerr << "QUERY FAILED: " << mysql_error(conn) << std::endl;
        std::cerr << "Неверный запрос в БД: " << query << std::endl;
    } else {
        MYSQL_RES *res = mysql_store_result(conn);
        if (res) {
            MYSQL_ROW row;
            unsigned int num_fields = mysql_num_fields(res);
            MYSQL_FIELD *fields = mysql_fetch_fields(res); // Получаем метаданные колонок

            // Инициализируем векторы для каждого поля
            for (unsigned int i = 0; i < num_fields; i++) {
                data[fields[i].name] = std::vector<std::string>();
            }

            while ((row = mysql_fetch_row(res))) {
                for (unsigned int i = 0; i < num_fields; i++) {
                    // Заполняем векторы соответствующими значениями
                    if (row[i]) {
                        data[fields[i].name].push_back(row[i]);
                    } else {
                        data[fields[i].name].push_back("NULL");
                    }
                }
            }
            mysql_free_result(res);
        }
    }
}    


// std::string value = data[0]["column_name"]; // Получение значения из первой строки для поля "column_name"
void executeQuery_select1(const char* query, std::unordered_map<int, std::unordered_map<std::string, std::string>>& data) {
    if (mysql_query(conn, query)) {
        std::cerr << "QUERY FAILED 1: " << mysql_error(conn) << std::endl;
        std::cerr << "Неверный запрос в БД: " << query << std::endl;
    } else {
        MYSQL_RES *res = mysql_store_result(conn);
        if (res) {
            MYSQL_ROW row;
            unsigned int num_fields = mysql_num_fields(res);
            MYSQL_FIELD *fields = mysql_fetch_fields(res); // Получаем метаданные колонок
            int row_index = 0; // Индекс для каждого ряда

            while ((row = mysql_fetch_row(res))) {
                std::unordered_map<std::string, std::string> row_map;
                for (unsigned int i = 0; i < num_fields; i++) {
                    if (row[i]) {
                        row_map[fields[i].name] = row[i];
                    } else {
                        row_map[fields[i].name] = "NULL";
                    }
                }

                // Добавляем ассоциативный массив в основной map по индексу
                data[row_index] = row_map;
                row_index++; // Увеличиваем индекс для следующей строки
            }
            mysql_free_result(res);
        }
    }
}

    
    bool executeQuery_insert(const char* query) {
        if (mysql_query(conn, query)) {
            std::cerr << "Error: " << mysql_error(conn) << std::endl;
            std::cerr << "Неверный запрос в БД: " << query << std::endl;
            return false;  // Запрос не выполнен успешно
        }
        return true;  // Запрос выполнен успешно
    }    
    
std::string AddSlashes(const std::string& input) {
    std::string escaped;
    for (char c : input) {
        if (c == '\\' || c == '\'' || c == '"' || c == ';' || c == '/' || c == '%') {
            escaped += '\\'; // Добавляем обратный слэш перед спецсимволами
        }
        escaped += c; // Добавляем текущий символ к результирующей строке
    }
    return escaped;
}    
    
std::string AddSlashes_bash(const std::string& input) {
    std::string escaped;
    for (char c : input) {
        if (c == '\\' || c == '\'' ) {
            escaped += '\\'; // Добавляем обратный слэш перед спецсимволами
        }
        escaped += c; // Добавляем текущий символ к результирующей строке
    }
    return escaped;
}    
    
    
    
    ~Database() {
        if (conn) {
            mysql_close(conn);
        }
    }

private:
    Database() : conn(nullptr) {} // Приватный конструктор
    Database(const Database&) = delete; // Запрет копирования
    Database& operator=(const Database&) = delete; // Запрет присваивания

    MYSQL *conn;
};


int mariadb() {
    Database& db = Database::getInstance();
    sqlDB sql_init_struct;

if (!db.connect(sql_init_struct.sql_host.c_str(), sql_init_struct.sql_login.c_str(), sql_init_struct.sql_passwd.c_str(), sql_init_struct.sql_db.c_str())) {
    std::cerr << "Ошибка при подключении к базе данных." << std::endl;
    return EXIT_FAILURE;
}


    // Пример запроса к базе данных
    //db.executeQuery("SELECT * FROM your_table;");
    
    //std::unordered_map<std::string, std::vector<std::string>> resultData;
    //const char* query = "SELECT * FROM your_table"; // Замените на свой запрос
    //db.executeQuery_select(query, resultData);

    // Пример вывода результатов
    //for (const auto& [key, values] : resultData) {
    //    std::cout << key << ": ";
    //    for (const auto& value : values) {
    //        std::cout << value << " ";
    //    }
    //    std::cout << std::endl;
    //}

        // Создаем пример данных
//     std::unordered_map<std::string, std::vector<std::string>> resultData = {
//         {"key1", {"value1a", "value1b"}},
//         {"key2", {"value2a"}},
//         {"key3", {"value3a", "value3b", "value3c"}}
//     };

    
    
    
    return EXIT_SUCCESS;
}
Если сборка проекта только make командой

Код: Выделить всё

make -j$(nproc)
то, перед компиляцией необходимо добавить в Makefile

Код: Выделить всё

# Пути к библиотекам и заголовочным файлам
INCLUDES = -I/usr/include/mariadb/mysql
LIBS = -L/usr/lib/mysql -lmariadb -lmysqlcppconn -lmysqlclient_r -pthread
Если сборка проекта cmake и make командами

Код: Выделить всё

cmake .
make -j$(nproc)
то, перед компиляцией необходимо добавить в CMakeLists.txt

Код: Выделить всё

#MySQL
# Добавьте include директорию
target_include_directories(имя_проекта PRIVATE /usr/include/mariadb/mysql)
# Укажите путь к библиотекам (если необходимо)
target_link_directories(имя_проекта PRIVATE /usr/lib/mysql)
# Линковка библиотек
target_link_libraries(имя_проекта
    mariadb
    mysqlcppconn
    mysqlclient_r
    pthread
)
в этом случае (Makefile будет создан автоматичеки) "имя_проекта" в CMakeLists.txt замените на своё, как указано в project(имя_проекта)
Если сборка проекта из командной строки:

Код: Выделить всё

g++ -std=c++11 -o исполняемый_файл проект.cpp -I/usr/include/mariadb/mysql -L/usr/lib/mysql -lmariadb -lmysqlcppconn -lmysqlclient_r -pthread
Пример подключения и использования библиотеки mariadb.hpp в проект.cpp

Код: Выделить всё

#include "config.hpp"
#include "mariadb.hpp"
using namespace std;
int main() {
	mariadb();
	Database& db = Database::getInstance();
	string query = "INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...)";
	if(db.executeQuery_insert(query.c_str()) )
	{ ... }
return 0;
}
для приведения типа std::to_string(переменная_другого_типа) к типу std::string в переменной query