Введение
Модуль Qt SQL предоставляет единый высокоуровневый интерфейс для работы с разными СУБД — SQLite, MySQL, PostgreSQL и другими — через систему драйверов. Это позволяет писать код, который при необходимости можно перенести с одной базы данных на другую с минимальными изменениями, поскольку основная логика взаимодействия (подключение, выполнение запросов, обработка результатов) остаётся одинаковой независимо от конкретной СУБД. В статье разберём, как подключаться к трём самым распространённым базам данных.
Концепция
QSqlDatabase::addDatabase(driverName) создаёт объект подключения, привязанный к конкретному драйверу — "QSQLITE" для SQLite, "QMYSQL" для MySQL, "QPSQL" для PostgreSQL. После создания объекта задаются параметры подключения (имя хоста, порт, имя базы данных, учётные данные), и вызывается open() для фактического установления соединения. Подключения именуются (по умолчанию — «безымянное» подключение, единственное на приложение) — для работы с несколькими базами одновременно используется именованный параметр addDatabase(driver, connectionName).
Пример кода: QSqlDatabase
#include <QCoreApplication>
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>
bool connectSqlite()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "sqlite_connection");
db.setDatabaseName("local_data.db");
if (!db.open()) {
qWarning() << "Ошибка подключения к SQLite:" << db.lastError().text();
return false;
}
qDebug() << "Подключение к SQLite установлено";
return true;
}
bool connectPostgres()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", "postgres_connection");
db.setHostName("localhost");
db.setPort(5432);
db.setDatabaseName("myapp_production");
db.setUserName("app_user");
db.setPassword(qgetenv("DB_PASSWORD")); // пароль из переменной окружения, не хардкод
if (!db.open()) {
qWarning() << "Ошибка подключения к PostgreSQL:" << db.lastError().text();
return false;
}
qDebug() << "Подключение к PostgreSQL установлено";
return true;
}
bool connectMysql()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "mysql_connection");
db.setHostName("localhost");
db.setDatabaseName("myapp");
db.setUserName("app_user");
db.setPassword(qgetenv("DB_PASSWORD"));
db.setConnectOptions("MYSQL_OPT_RECONNECT=1");
if (!db.open()) {
qWarning() << "Ошибка подключения к MySQL:" << db.lastError().text();
return false;
}
qDebug() << "Подключение к MySQL установлено";
return true;
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
qDebug() << "Доступные драйверы:" << QSqlDatabase::drivers();
connectSqlite();
return 0;
}
Пояснения к коду
Каждая функция создаёт независимое именованное подключение через addDatabase(driver, connectionName), что позволяет приложению одновременно работать, например, с локальной SQLite-кэш базой и удалённой PostgreSQL — оба подключения существуют параллельно и не конфликтуют друг с другом. setConnectOptions("MYSQL_OPT_RECONNECT=1") в примере с MySQL — специфичная для драйвера опция, демонстрирующая, что несмотря на единый высокоуровневый интерфейс, некоторые тонкие настройки всё же специфичны для конкретной СУБД.
Пароль передаётся через qgetenv("DB_PASSWORD"), а не хардкодится в исходном коде — это базовая практика безопасности, предотвращающая попадание учётных данных в систему контроля версий.
Подводные камни
- Хардкод учётных данных непосредственно в исходном коде, который попадает в репозиторий — классическая утечка секретов; пароли и строки подключения должны браться из переменных окружения, защищённого хранилища конфигурации или файлов, явно исключённых из системы контроля версий.
- Отсутствие проверки результата
open(). Без проверки булевого результата код может продолжить выполнение, считая, что подключение установлено, и последующие запросы будут проваливаться с малопонятными ошибками — каждый вызовopen()должен сопровождаться проверкой и логированиемdb.lastError()при сбое. - Использование одного и того же безымянного подключения (без указания
connectionName) из нескольких потоков.QSqlDatabaseне является потокобезопасным для совместного использования одного подключения несколькими потоками одновременно — каждый поток, работающий с базой данных, должен иметь собственное именованное подключение. - Отсутствие драйвера для конкретной СУБД в сборке Qt. Драйверы
QMYSQL/QPSQLчасто требуют отдельной установки клиентских библиотек СУБД и могут не входить в стандартную сборку Qt по умолчанию на некоторых платформах — перед использованием стоит проверитьQSqlDatabase::isDriverAvailable()и обеспечить наличие нужных системных библиотек на целевой машине.