Эта заметка вкратце познакомит вас с основами использования модулей Qt для работы с реляционными базами данных. Предполагается, что знание SQL у вас уже имеется, хотя и не является столь критичным для понимания представленных примеров.
Рассматриваются базовые операции, необходимые для начала работы:
Для того, чтобы встроенные в Qt возможности для работы с SQL заработали, необходимо добавить в pro
-файл следующую инструкцию:
QT += sql
Однако учитывайте, что драйвера различных баз данных устанавливаются в виде плагинов и могут отсутствовать в вашем дистрибутиве Qt. Особенно актуальной это проблема является под Windows в связи с лицензионными ограничениями на распространение бинарных пакетов. О том, как собрать нужный плагин, мы поговорим в другой раз.
Для простоты воспользуемся драйвером QSQLITE
(предназначен для работы с SQLite
), поскольку он предустановлен во всех известных мне дистрибутивах Qt. К тому же, вам не потребуется устанавливать отдельную систему управлениями базами данных.
Рассмотрим соответствующий код подключения:
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDate>
int main() {
QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
db.setDatabaseName( "test" );
if( !db.open() ) {
qDebug() << db.lastError().text();
return 1;
}
return 0;
}
Если все прошло нормально, то в результате работы этого кода у вас появится пустой файл test
в рабочем каталоге приложения. Так же обратите внимание на следующие функции-члены класса QSqlDatabase
, которые потребуются вам, когда вы решите воспользоваться внешним сервером баз данных:
isValid();
setHostName();
setPort();
setDatabaseName();
setUserName();
setPassword();
Создадим в открытой базе данных новую таблицу с помощью QSqlQuery
:
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDate>
int main() {
// Предыдущий код убран для краткости
QSqlQuery query( db );
if( !query.exec(
"CREATE TABLE User("
" login VARCHAR( 200 ) NOT NULL,"
" registration_date DATE NOT NULL"
")"
) ) {
qDebug() << db.lastError().text();
return 1;
}
return 0;
}
Аналогичным образом с помощью функции-члена exec()
можно выполнять любые запросы к базе данных. Однако имеется одна тонкость.
Если запрос использует внешние данные, то в целях безопасности не вставляйте их напрямую, а используйте комбинацию prepare()
и bindValue()
:
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDate>
int main() {
// Предыдущий код убран для краткости
query.prepare(
"INSERT INTO User( login, registration_date ) "
" VALUES( :login, :registration_date )"
);
query.bindValue( ":login", "Hello" );
query.bindValue( ":registration_date", QDate::currentDate() );
if( !query.exec() ) {
qDebug() << db.lastError().text();
return 1;
}
return 0;
}
Теперь рассмотрим способ получения записей из базы данных:
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDate>
int main() {
// Предыдущий код убран для краткости
if( !query.exec( "SELECT * FROM User" ) ) {
qDebug() << db.lastError().text();
return 1;
}
QSqlRecord rec = query.record();
const int loginIndex = rec.indexOf( "login" );
const int registrationDateIndex = rec.indexOf( "registration_date" );
while( query.next() ) {
qDebug() << query.value( loginIndex ) << query.value( registrationDateIndex );
}
return 0;
}
Подводя итоги приведу полный листинг рассмотренного примера (обратите внимание на его завершение, дополненное кодом удаления таблицы и закрытия соединения с базой данных):
#include <QDebug>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
#include <QDate>
int main() {
QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" );
db.setDatabaseName( "test" );
if( !db.open() ) {
qDebug() << db.lastError().text();
return 1;
}
QSqlQuery query( db );
if( !query.exec(
"CREATE TABLE User("
" login VARCHAR( 200 ) NOT NULL,"
" registration_date DATE NOT NULL"
")"
) ) {
qDebug() << db.lastError().text();
return 1;
}
query.prepare(
"INSERT INTO User( login, registration_date ) "
" VALUES( :login, :registration_date )"
);
query.bindValue( ":login", "Hello" );
query.bindValue( ":registration_date", QDate::currentDate() );
if( !query.exec() ) {
qDebug() << db.lastError().text();
return 1;
}
if( !query.exec( "SELECT * FROM User" ) ) {
qDebug() << db.lastError().text();
return 1;
}
QSqlRecord rec = query.record();
const int loginIndex = rec.indexOf( "login" );
const int registrationDateIndex = rec.indexOf( "registration_date" );
while( query.next() ) {
qDebug() << query.value( loginIndex ) << query.value( registrationDateIndex );
}
// Удаляем таблицу перед выходом
query.exec( "DROP TABLE User" );
// Не обязательно, но в крупной системе лучше закрывать соединение с БД, когда оно больше не требуется
db.close();
return 0;
}