Программирование баз данных с помощью Qt. Исполнение команд SQL в Qt

Программирование баз данных с помощью Qt. Исполнение команд SQL в Qt

27.04.2019

Qt дает возможность создания платформо-независимых приложений для работы с базами данных, используя стандартные СУБД. Qt включает «родные» драйвера для Oracle, Microsoft SQL Server, Sybase Adaptive Server, IBM DB2, PostgreSQL, MySQL и ODBC-совместимых баз данных. Qt включает специфичные для баз данных виджеты, а также поддерживает расширение для работы с базами данных любых встроенных или отдельно написанных виджетов.

Введение

Работа с базами данных в Qt происходит на различных уровнях:

1.Слой драйверов - Включает классы QSqlDriver, QSqlDriverCreator, QSqlDriverCreatorBase, QSqlDriverPlugin и QSqlResult. Этот слой предоставляет низкоуровневый мост между определенными базами данных и слоем SQL API.

2.Слой SQL API - Этот слой предоставляет доступ к базам данных. Соединения устанавливаются с помощью класса QSqlDatabase. Взаимодействие с базой данных осуществляется с помощью класса QSqlQuery. В дополнение к классам QSqlDatabase и QSqlQuery слой SQL API опирается на классы QSqlError, QSqlField, QSqlIndex и QsqlRecord.

3.Слой пользовательского интерфейса - Этот слой связывает данные из базы данных с дата-ориентироваными виджетами. Сюда входят такие классы, как QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel.

Соединение с базой данных

Чтобы получить доступ к базе данных с помощью QSqlQuery и QSqlQueryModel, необходимо создать и открыть одно или более соединений с базой данных.

Qt может работать со следующими базами данных (из-за несовместимости с GPL лицензией, не все плагины поставляются с Qt Open Source Edition):

  • QDB2 - IBM DB2 (версия 7.1 и выше
  • QIBASE - Borland InterBase
  • QMYSQL - MySQL
  • QOCI - Драйвер Oracle Call Interface
  • QODBC - Open Database Connectivity (ODBC) - Microsoft SQL Server и другие ODBC-совместимые базы данных
  • QPSQL - PostgreSQL (версия 7.3 и выше)
  • QSQLITE2 - SQLite версии 2
  • QSQLITE - SQLite версии 3
  • QTDS - Драйвер Sybase Adaptive Server

Для сборки плагина драйвера, которые не входят в поставку Qt нужно иметь соответствующую клиентскую библиотеку для используемой СУБД.

Соединиться с базой данных можно вот так:

QSqlDatabase db = QsqlDatabase::addDatabase("QMYSQL", "mydb");

db.setHostName("bigblue");

db.setDatabaseName("flightdb");

db.setUserName("acarlson");

db.setPassword("1uTbSbAs");

bool ok = db.open();

Первая строка создает объект соединения, а последняя открывает его. В промежутке инициализируется некоторая информация о соединении, включая имя соединения, имя базы данных, имя узла, имя пользователя, пароль. В этом примере происходит соединение с базой данных MySQL flightdb на узле bigblue. Аргумент «QMYSQL» в addDatabase() указывает тип драйвера базы данных, чтобы использовать для соединения, а «mydb» - имя соединения.

Как только соединение установлено, можно вызвать статическую функцию QSqlDatabase::database() из любого места программы с указанием имени соединения, чтобы получить указатель на это соединение. Если не передать имя соединения, она вернет соединение по умолчанию.

Если open() потерпит неудачу, он вернет false. В этом случае, можно получить информацию об ошибке, вызвав QSqlDatabase::lastError().

Для удаления соединения с базой данных, надо сначала закрыть базу данных с помощью QSqlDatabase::close(), а затем, удалить соединение с помощью статического метода QSqlDatabase::removeDatabase().

Выполнение инструкций SQL

Класс QSqlQuery обеспечивает интерфейс для выполнения SQL запросов и навигации по результирующей выборке. Для выполнения SQL запросов, просто создают объект QSqlQuery и вызывают QSqlQuery::exec(). Например, вот так:

QSqlQuery query;

query.exec("SELECT name, salary FROM employee WHERE salary > 50000");

Конструктор QSqlQuery принимает необязательный аргумент QSqlDatabase, который уточняет, какое соединение с базой данных используется. Если его не указать, то используется соединение по умолчанию. Если возникает ошибка, exec() возвращает false. Доступ к ошибке можно получить с помощью QSqlQuery::lastError().

QSqlQuery предоставляет единовременный доступ к результирующей выборке одного запроса. После вызова exec(), внутренний указатель QSqlQuery указывает на позицию перед первой записью. Если вызвать метод QSqlQuery::next() один раз, то он переместит указатель к первой записи. После этого необходимо повторять вызов next(), чтобы получать доступ к другим записям, до тех пор пока он не вернет false.

Вот типичный цикл, перебирающий все записи по порядку:

while (query.next()) {

QString name = query.value(0).toString();

int salary = query.value(1).toInt();

qDebug() << name << salary;

QSqlQuery может выполнять не только SELECT, но также и любые другие запросы. Следующий пример вставляет запись в таблицу, используя INSERT:

QSqlQuery query;

query.exec("INSERT INTO employee (id, name, salary) "

"VALUES (1001, "Thad Beaumont", 65000)");

Если надо одновременно вставить множество записей, то зачастую эффективней отделить запрос от реально вставляемых значений. Это можно сделать с помощью вставки значений через параметры. Qt поддерживает два синтаксиса вставки значений: поименованые параметры и позиционные параметры. В следующем примере показана вставка с помощью поименованного параметра:

QSqlQuery query;

"VALUES (:id, :name, :salary)");

query.bindValue(":id", 1001);

query.bindValue(":name", "Thad Beaumont");

query.bindValue(":salary", 65000);

В этом примере показана вставка с помощью позиционного параметра:

QSqlQuery query;

query.prepare("INSERT INTO employee (id, name, salary) "

"VALUES (?, ?, ?)");

query.addBindValue(1001);

query.addBindValue("Thad Beaumont");

query.addBindValue(65000);

При вставке множества записей требуется вызвать QSqlQuery::prepare() только однажды. Далее можно вызвать bindValue() или addBindValue() с последующим вызовом exec() столько раз, сколько потребуется.

Отображение данных в таблице-представлении

Классы QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel могут использоваться в качестве источников данных для классов представлений Qt, таких как QListView, QTableView и QTreeView. На практике наиболее часто используется QTableView в связи с тем, что результирующая SQL выборка, по существу, представляет собой двумерную структуру данных.

В следующем примере создается представление основанное на модели данных SQL:

QSqlTableModel model;

model.setTable("employee");

QTableView *view = new QTableView;

view->setModel(model);

view->show();

Если модель является моделью для чтения-записи (например, QSqlTableModel), то представление позволяет редактировать поля. Это можно отключить с помощью следующего кода

view->setEditTriggers(QAbstractItemView::NoEditTriggers);

Можно использовать одну и ту-же модель в качестве источника данных для нескольких представлений. Если пользователь изменяет данные модели с помощью одного из представлений, другие представления немедленно отобразят изменения.

Классы-представления для обозначения колонок наверху отображают заголовки. Для изменения текста заголовка, используется функция setHeaderData() модели. Например:

model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));

model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));

model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));

model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));

Заключение

В данной статье изложены базовые принципы работы с базами данных в Qt. Однако кроме указанных здесь возможностей еще много интересного, например, транзакции, работа с внешними ключами или создание дата-ориентированых форм. К сожалению эти темы достаточно обширны для одной статьи.

База данных представляет собой систему хранения записей, организованных в виде таблиц. База данных может содержать от одной до нескольких сотен таблиц, которые бывают связаны между собой. Таблица состоит из набора строк и столбцов. Столбцы таблицы имеют имена и за каждым из них закреплен тип и/или область значения. Строки таблицы баз данных называются записями, а ячейки, на которые делится запись, — полями.

Первичный ключ — это уникальный идентификатор, который может представлять собой не только один столбец, но и целую комбинацию столбцов.

Пользователь может выполнять множество разных операций с таблицами, например: добавлять, изменять и удалять записи, вести поиск и т. д. Для составления подобного рода запросов был разработан язык SQL (Structured Query Language, язык структурированных запросов), который дает возможность не только осуществлять запросы и изменять данные, но и создавать новые базы данных.

Основными действиями, производимыми с базой данных, являются создание новой таблицы, чтение (выборка и проекция), вставка, изменение и удаление данных. Сразу следует сказать, что язык SQL нечувствителен к регистру, а это значит, что буква, набранная в верхнем или нижнем регистре, считается одной и той же. Например, SELECT = select = Select и т. д. В дальнейшем, для выделения ключевых слов SQL будем использовать верхний регистр.

Язык запросов SQL — это стандарт, который используется в большом количестве СУБД, что обеспечивает его платформонезависимость. Запросы (команды) — это своего рода вопросы, задаваемые базе данных, на которые она должна давать ответы.

Для работы с базой данных нужно сначала активизировать драйвер, а затем установить связь с базой данных. После этого посредством запросов SQL можно получать, вставлять, изменять и удалять данные.

Qt представляет модуль поддержки баз данных, классы которого разделены натри уровня: уровень драйверов, программный и пользовательский. Прежде чем начать работу с базой данных, необходимо соединиться с ней, активизировав драйвер. Запросы оформляются в виде строки. Для высылки запросов используется класс QSqlQuery .

При помощи концепции Интервью можно легко отображать данные SQL-моделей в представлениях.

Создание таблицы

Для создания таблицы используется оператор CREATE TABLE, в котором указываются имена столбцов таблицы, их тип, а также задается первичный ключ:

CREATE TABLE addressbook (number INTEGER PRIMARY KEY NOT NULL, name VARCHAR(15), phone VARCHAR(12), email VARCHAR(15));

Операция вставки

После создания таблицы можно добавлять данные. Для этого SQL предоставляет оператор вставки insert into. Сразу после названия таблицы нужно указать в скобках имена столбцов, в которые будут заноситься данные.

Сами данные указываются после ключевого слова values.

INSERT INTO addressbook (number, name, phone, email) VALUES(1, "Piggy", "+49 631322187", "[email protected]"); INSERT INTO addressbook (number, name, phone, email) VALUES(2, "Kermit", "+49 631322181", "[email protected]");

Чтение данных

Составной оператор select ... from ... where осуществляет операции выборки и проекции. Выборка соответствует выбору строк, а проекция — выбору столбцов. Этот оператор возвращает таблицу, созданную согласно заданным критериям.

  • Ключевое слово SELECT является оператором для проведения проекции, то есть в нем указываются столбцы, которые должны стать ответом на запрос. Если указать после SELECT знак *, то результирующая таблица будет содержать все столбцы таблицы, к которой был адресован запрос. Указание конкретных имен столбцов устраняет в ответе все остальные.
  • Ключевое слово FROM задает таблицу, к которой адресован запрос.
  • Ключевое слово WHERE является оператором выборки. Выборка осуществляется согласно условиям, указанным сразу после оператора.

Например, для получения адреса электронной почты мисс Piggy нужно сделать следующее:

SELECT email FROM addressbook WHERE name = "Piggy";

Изменение данных

Для изменения данных таблицы используется составной оператор UPDATE ... SET . После названия таблицы в операторе SET указывается название столбца (или столбцов, через запятую), в который будет заноситься нужное значение. Изменение данных производится в строках, удовлетворяющих условию, поставленному в ключевом слове WHERE .

В показанном ниже примере производится замена адреса электронной почты мисс Piggy с [email protected] на [email protected]:

UPDATE addressbook SET email = "[email protected]" WHERE name = "Piggy";

Удаление

Удаление строк из таблицы производится при помощи оператора DELETE ... FROM . После ключевого слова WHERE следует критерий, согласно которому производится удаление строк. Например, удалить адрес мисс Piggy из таблицы можно следующим образом:

DELETE FROM addressbook WHERE name = "Piggy";

Qt является одним из самых популярных и удобных фреймворков для разработки, и это вполне заслуженно. Когда нашей компании пришёл заказ на небольшое клиент-серверное приложение, мы ни минуты не сомневались в выборе инструментария. Приложение должно было работать на Windows и Linux, впоследствии к списку платформ добавился и Android. Приложение является сетевым, решает довольно простенькую задачу, и хранит все свои данные на сервере MySQL.
И тут начала вырисовываться проблема: как запрячь в одну упряжку Qt-приложение, Android, да ещё и заставить их общаться с MySQL? Решению этой достаточно нетривиальной задачи и посвящена эта статья. В качестве примера напишем небольшое приложение, которое считывает строки из таблицы MySQL и выводит их в табличное поле на форме.

Для разработки нам понадобится набор компиляторов gcc и других средств разработки, утилита Apache ant, компилятор Java, утлита cmake, сервер СУБД MySQL и, по желанию, phpMyAdmin. Устанавливаем их:

Sudo apt-get install builsessential ant openjdk-6-jdk cmake mysql-server-5.1 phpmyadmin mysql-server-core-5.1

Остальные пакеты подтянутся по зависимостям.

Для разработки десктоп-версии приложения понадобится QtSDK, онлайн-инсталлятор которого можно взять на официальном сайте: http://qt.nokia.com/downloads/ .

Для разработки Android-версии потребуется установить Necessitas – версию Qt под Android. Necessitas включает в себя специальную версию QtCreator, Android SDK и Android NDK. Онлайн-инсталлятор можно взять по адресу , при установке обязательно нужно отметить установку исходных текстов Qt.
Теперь осталось установить бинарный драйвер для доступа к MySQL. В базовую поставку Qt он не входит, поэтому его следует скачивать или собирать отдельно. Для пользователей Ubuntu это не составляет проблемы: достаточно установить пакет libqt4-sql-mysql:

Sudo apt-get install libqt4-sql-mysql

После чего нужно скопировать библиотеку в папку с установленным Qt SDK:

Cp /usr/lib/x86_64-linux-gnu/qt4/plugins/sqldrivers/libqsqlmysql.so /path/to/QtSDK/Desktop/Qt/480/gcc/plugins/sqldrivers/libqsqlmysql.so

Другим же придётся собирать его самостоятельно.
После этого можно приниматься за разработку программы. Для начала откроем QtCreator и создадим пустой проект QtGUI c одной формой:

Положим на форму QTableWidget и назовём его tw, укажем выравнивание контролов по сетке.

Чтобы добавить поддержку MySQL в приложение, добавим в проект зависимость от модуля QtSQL:

Создадим на сервере MySql базу данных sample с таблицей tab из трёх колонок. Допустим, таблица будет хранить номер, имя и возраст человека. Я предпочитаю использовать для этого phpMyAdmin:

Теперь добавим к нашему приложению код для чтения данных из таблицы:

Компилируем, запускаем, убеждаемся, что всё работает:

Наше приложение готово. Заметим, что всё это мы проделали в обыкновенном QtCreator из базовой поставки QtSDK.

Теперь пришла пора портировать приложение под android. Прежде всего, нужно приготовить виртуальные устройства, на которых будем запускать его для тестирования. Для этого заходим в каталог с установленным Android SDK (у меня это ~/necessitas/android-sdk/) и запускаем скрипт android из подкаталога tools.
Запустив команду Tools - Manage AVDs, можно открыть менеджер виртуальных устройств.
Мы создадим два виртуальных устройства. Одно будет с архитектурой armeabi:

.

Другое будет с архитектурой armeabi-v7a:

.

Теперь сделаем резервную копию нашего проекта и запустим Necessits QtCreator.
Прежде всего нужно зайти в Tools - Options - Android и убедиться, что всё настроено:

.

Открываем наш проект и добавляем цели сборки:

.

Жмём Finish и пробуем запустить проект.
Разумеется, сначала ничего не заработает: нужно установить прослойку Ministro, которая содержит рантайм-компоненты, необходимые для запуска Qt-приложений под Android.
Запустив виртуальное устройство, открываем браузер, вводим в поисковую строку Google «Ministro» и по второй ссылке переходим на официальный сайт, откуда скачиваем и устанавливаем последний релиз. После установки можно попробовать запустить приложение ещё раз - Ministro скачает и установит необходимые библиотеки.

Приложение запустится, но не сможет работать корректно по причине отсутствия самого главного компонента - драйвера для доступа к MySql:

Перед сборкой драйвера сначала нужно скомпилировать под Android библиотеку libmysql.
Берём исходники здесь: www.mysql.com/downloads/connector/c и распаковываем в нужную папку. Перед сборкой в папке с исходниками нужно создать файл toolchain.cmake, который описывает правила сборки под нужную нам архитектуру. Образец можно скачать, например, здесь: https://github.com/qgis/qgis-android/blob/master/scripts/android.toolchain.cmake , его нужно будет немного модифицировать:

1. В строке set(ANDROID_NDK_DEFAULT_SEARCH_PATH /path/to/android-ndk) указать путь, по которому расположен Android-ndk.
2. В строке set(ANDROID_NDK_TOOLCHAIN_DEFAULT_SEARCH_PATH /path/to/toolchain) указать путь, по которому расположен набор инструментов сборки.

Назовём отредактированный файл, скажем, android.cmake
Отдаём команды:

Export ANDROID_NDK=/full/path/to/necessitas/android-ndk
cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/mysql-connector-c-6.0.2/android.cmake
make

При сборке могут возникать некоторые легко устранимые ошибки, связанные, в основном, с отсутствием нескольких заголовочных файлов. Они легко устраняются, так что подробно останавливаться на них я не буду.
После завершения сборки в каталоге libs мы получим файл libmysql.so.16.0.0, собранный для архитектуры armeabi-v7a.

Теперь заново распаковываем исходники в другую папку, изменяем в файле android.cmake строку

Set(ARM_TARGET "armeabi-v7a" CACHE STRING "the arm target for android, recommend armeabi-v7a for floating point support and NEON.")

Set(ARM_TARGET "armeabi" CACHE STRING "the arm target for android, recommend armeabi-v7a for floating point support and NEON.")

И повторяем процедуру. Получим файл libmysql.so.16.0.0, собранный для архитектуры armeabi.
Скопируем оба варианта в удобный каталог, допустим, в ~/libs/armeabi и ~/libs/armeabi-v7a.
Теперь снова запускаем Necessitas QtCreator, открываем проект /path/to/necessitas/Android/Qt/480/qt-src/src/plugins/sqldrivers/mysql/mysql.pro и добавляем цели сборки для Android:

Для сборки потребуется поместить в каталог /path/to/necessitas/Android/Qt/480/qt-src/src/sql/drivers/mysql/ следующие файлы из каталога mysql-connector-c-6.0.2/include/:

  • mysql.h
  • my_alloc.h
  • my_list.h
  • mysql_com.h
  • mysql.h
  • mysql_time.h
  • mysql_version.h
  • typelib.h
Также следует отредактировать файл qsql_mysql.h, заменив угловые скобки в инструкции #include на кавычки.
Указываем цель сборки: Necessitas Qt 4.8.0 for Android armv5 Release. После этого следует подключить к проекту библиотеку mysqlclient, для чего щёлкаем правой кнопкой по корневой папке mysql, выбираем пункт «Add library». Далее выбираем External library и затем указываем путь к файлу libmysqlclient.a:

Сохраняем проект и выполняем команду Build - Build all.
В каталоге /path/to/necessitas/Android/Qt/480/qt-src/src/plugins/sqldrivers/mysql-build-Necessitas_Qt_4_8_0_for_Android_armv5_Release/ получим библиотеку libqsqlmysql.so - это и есть наш долгожданный драйвер для доступа к MySQL, собранный под архитектуру armeabi.
Теперь указываем цель сборки Necessitas Qt 4.8.0 for Android armv7a Release, затем удаляем из файла mysql.pro все упоминания об lmysqlclient, и добавляем библиотеку уже для архитекутры armeabi-v7a. После сборки получим в каталоге /path/to/necessitas/Android/Qt/480/qt-src/src/plugins/sqldrivers/mysql-build-Necessitas_Qt_4_8_0_for_Android_armv7a_Release/ драйвер для доступа к MySQL, собранный уже для armeabi-v7a.
Теперь можно скопировать собранные библиотеки в удобное место и снова попробовать собрать наше приложение под Android. Для этого открываем в Necessitas QtCreator наш проект-пример и добавляем к проекту зависимость от ранее скомпилированной библиотеки libqsqlmysql.so. Проще всего это сделать, добавив в *.pro-файл строчку

LIBS += -L/path/to/libs/armeabi/ -lqsqlmysql

После этого в опциях запуска приложения указываем, что необходимо закачать в эмулятор библиотеки Qt с локального компьютера.

Запускаем приложение. Если все было скомпилировано правильно, оно должно заработать:

Самое главное позади - проект успешно собран, и запускается на виртуальном устройстве.
Осталась последняя, но немаловажная часть: собрать дистрибутив приложения так, чтобы оно могло запускаться без пинка со стороны QtCreator.
К сожалению, в текущей версии necessitas имеет неприятную недоработку: дополнительные библиотеки, динамически подключаемые к приложению, не попадают в финальный дистрибутив. Обойти это можно, если зайти в каталог /path/to/project/android/res/values/ и отредактировать файл libs.xml: здесь нужно заменить массив


массивом следующего вида:

libqsqlmysql.so
Поскольку приложение уже собрано, нам остаётся только положить в каталог libs означенную библиотеку, вернуться в корневой каталог проекта и отдать в консоли команду

Ant clean release

После завершения сборки в подкаталоге bin каталога с проектом мы получим готовый к установке на реальное устройство apk-пакет. Аналогичным образом создаётся приложение для архитектуры armeabi-v7a.

Qt дает возможность создания платформо-независимых приложений для работы с базами данных, используя стандартные СУБД. Qt включает «родные» драйвера для Oracle, Microsoft SQL Server, Sybase Adaptive Server, IBM DB2, PostgreSQL, MySQL и ODBC-совместимых баз данных. Qt включает специфичные для баз данных виджеты, а также поддерживает расширение для работы с базами данных любых встроенных или отдельно написанных виджетов.

Введение

Работа с базами данных в Qt происходит на различных уровнях:
1.Слой драйверов - Включает классы QSqlDriver, QSqlDriverCreator, QSqlDriverCreatorBase, QSqlDriverPlugin и QSqlResult. Этот слой предоставляет низкоуровневый мост между определенными базами данных и слоем SQL API.
2.Слой SQL API - Этот слой предоставляет доступ к базам данных. Соединения устанавливаются с помощью класса QSqlDatabase. Взаимодействие с базой данных осуществляется с помощью класса QSqlQuery. В дополнение к классам QSqlDatabase и QSqlQuery слой SQL API опирается на классы QSqlError, QSqlField, QSqlIndex и QsqlRecord.
3.Слой пользовательского интерфейса - Этот слой связывает данные из базы данных с дата-ориентироваными виджетами. Сюда входят такие классы, как QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel.

Соединение с базой данных

Чтобы получить доступ к базе данных с помощью QSqlQuery и QSqlQueryModel, необходимо создать и открыть одно или более соединений с базой данных.
Qt может работать со следующими базами данных (из-за несовместимости с GPL лицензией, не все плагины поставляются с Qt Open Source Edition):
  1. QDB2 - IBM DB2 (версия 7.1 и выше
  2. QIBASE - Borland InterBase
  3. QMYSQL - MySQL
  4. QOCI - Драйвер Oracle Call Interface
  5. QODBC - Open Database Connectivity (ODBC) - Microsoft SQL Server и другие ODBC-совместимые базы данных
  6. QPSQL - PostgreSQL (версия 7.3 и выше)
  7. QSQLITE2 - SQLite версии 2
  8. QSQLITE - SQLite версии 3
  9. QTDS - Драйвер Sybase Adaptive Server
Для сборки плагина драйвера, которые не входят в поставку Qt нужно иметь соответствующую клиентскую библиотеку для используемой СУБД.

Соединиться с базой данных можно вот так:

  1. QSqlDatabase db = QsqlDatabase::addDatabase("QMYSQL" , "mydb" );
  2. db.setHostName("bigblue" );
  3. db.setDatabaseName("flightdb" );
  4. db.setUserName("acarlson" );
  5. db.setPassword("1uTbSbAs" );
  6. bool ok = db.open();

Первая строка создает объект соединения, а последняя открывает его. В промежутке инициализируется некоторая информация о соединении, включая имя соединения, имя базы данных, имя узла, имя пользователя, пароль. В этом примере происходит соединение с базой данных MySQL flightdb на узле bigblue. Аргумент «QMYSQL» в addDatabase() указывает тип драйвера базы данных, чтобы использовать для соединения, а «mydb» - имя соединения.
Как только соединение установлено, можно вызвать статическую функцию QSqlDatabase::database() из любого места программы с указанием имени соединения, чтобы получить указатель на это соединение. Если не передать имя соединения, она вернет соединение по умолчанию.
Если open() потерпит неудачу, он вернет false. В этом случае, можно получить информацию об ошибке, вызвав QSqlDatabase::lastError().
Для удаления соединения с базой данных, надо сначала закрыть базу данных с помощью QSqlDatabase::close(), а затем, удалить соединение с помощью статического метода QSqlDatabase::removeDatabase().

Выполнение инструкций SQL

Класс QSqlQuery обеспечивает интерфейс для выполнения SQL запросов и навигации по результирующей выборке.
Для выполнения SQL запросов, просто создают объект QSqlQuery и вызывают QSqlQuery::exec(). Например, вот так:
  1. QSqlQuery query;
  2. query.exec("SELECT name, salary FROM employee WHERE salary > 50000" );
* This source code was highlighted with Source Code Highlighter .

Конструктор QSqlQuery принимает необязательный аргумент QSqlDatabase, который уточняет, какое соединение с базой данных используется. Если его не указать, то используется соединение по умолчанию.
Если возникает ошибка, exec() возвращает false. Доступ к ошибке можно получить с помощью QSqlQuery::lastError().
QSqlQuery предоставляет единовременный доступ к результирующей выборке одного запроса. После вызова exec(), внутренний указатель QSqlQuery указывает на позицию перед первой записью. Если вызвать метод QSqlQuery::next() один раз, то он переместит указатель к первой записи. После этого необходимо повторять вызов next(), чтобы получать доступ к другим записям, до тех пор пока он не вернет false. Вот типичный цикл, перебирающий все записи по порядку:
  1. while (query.next()) {
  2. QString name = query.value (0).toString();
  3. int salary = query.value (1).toInt();
  4. qDebug() << name << salary;
* This source code was highlighted with Source Code Highlighter .

QSqlQuery может выполнять не только SELECT, но также и любые другие запросы. Следующий пример вставляет запись в таблицу, используя INSERT:
  1. QSqlQuery query;
  2. query.exec(
  3. "VALUES (1001, "Thad Beaumont", 65000)" );
* This source code was highlighted with Source Code Highlighter .

Если надо одновременно вставить множество записей, то зачастую эффективней отделить запрос от реально вставляемых значений. Это можно сделать с помощью вставки значений через параметры. Qt поддерживает два синтаксиса вставки значений: поименованые параметры и позиционные параметры. В следующем примере показана вставка с помощью поименованного параметра:
  1. QSqlQuery query;
  2. query.prepare("INSERT INTO employee (id, name, salary) "
  3. "VALUES (:id, :name, :salary)" );
  4. query.bindValue(":id" , 1001);
  5. query.bindValue(":name" , "Thad Beaumont" );
  6. query.bindValue(":salary" , 65000);
  7. query.exec();
* This source code was highlighted with Source Code Highlighter .

В этом примере показана вставка с помощью позиционного параметра:
  1. QSqlQuery query;
  2. query.prepare("INSERT INTO employee (id, name, salary) "
  3. "VALUES (?, ?, ?)" );
  4. query.addBindValue(1001);
  5. query.addBindValue("Thad Beaumont" );
  6. query.addBindValue(65000);
  7. query.exec();
* This source code was highlighted with Source Code Highlighter .

При вставке множества записей требуется вызвать QSqlQuery::prepare() только однажды. Далее можно вызвать bindValue() или addBindValue() с последующим вызовом exec() столько раз, сколько потребуется.

Отображение данных в таблице-представлении

Классы QSqlQueryModel, QSqlTableModel и QSqlRelationalTableModel могут использоваться в качестве источников данных для классов представлений Qt, таких как QListView, QTableView и QTreeView. На практике наиболее часто используется QTableView в связи с тем, что результирующая SQL выборка, по существу, представляет собой двумерную структуру данных.
В следующем примере создается представление основанное на модели данных SQL:
  1. QSqlTableModel model;
  2. model.setTable("employee" );
  3. QTableView *view = new QTableView;
  4. view->setModel(&model);
  5. view->show();
* This source code was highlighted with Source Code Highlighter .

Если модель является моделью для чтения-записи (например, QSqlTableModel), то представление позволяет редактировать поля. Это можно отключить с помощью следующего кода
  • Tutorial

Добрый день.

Ниже пойдет речь о том, как использовать SQLite в . Автор постарался как можно подробнее рассматривать программирование баз данных в Qt.

Об этих двух замечательных продуктах можно прочитать следуя приведенным выше ссылкам, а мы будем конкретно рассматривать программирование БД в Qt, в частности, на примере SQLite. Скажу только, что SQLite несколько отличается от «обычных» баз данных, таких как MySQL тем, что «не обладает» клиент-серверной архитектурой. То есть движок БД не является отдельно работающим процессом, с которым взаимодействует программа. SQLite представляет собой библиотеку, с которой компонуется ваша программа и, таким образом, движок становится составной частью программы. То есть представьте вы решили сохранять все данные, с которыми «сталкивается» ваша программа в обычный файл. В один прекрасный день вы решаете сохранять данные в файле, но организовав это с «реляционной» точки зрения. После этого вы поняли, что новая структура файла должна «распознаваться особым образом». С этого, как минимум, следует, что вам нужно предоставить некоторый API, обеспечивающий связь между этим файлом данных с приложением. В общем, следуя логической постановке приведенного сценария у вас рождается система БД, не требующая сервера БД и собственно, клиента. Получается достаточно быстрая по сравнению с «клиент-серверной» БД система, и сама программа упрощается.

Я состою в дружеских отношениях с Qt и недавно мне понадобилось ее БД функциональность. С MySQL я тоже в достаточно дружеских отношениях и попытался использовать Qt с MySQL в программе, в то время разрабатываемой мной. Имея нехватку времени и нервов, чтоб «связать» MySQL с Qt, решил воспользоваться SQLite, для чего в Qt есть, так сказать, встроенная поддержка, то есть ничего нового установить/конфигурировать не надо было (это не относиться к случаю, если ваш Qt собран с поддержкой «считанных» модулей, без подключения модуля QtSql). И еще, если мне придется установить программу в другой компьютер, я не буду «вынужден» установить сервер MySQL и т.д. (спорная тема - знаю).

FIY

На данный момент я использую программу SQLiteManager для создания БД, таблиц и т.д., использую недавно, но программа сразу понравилась. В моей «рабочей лошадке» установлен(a?) Qt Windows SDK и я использую QtCreator, сразу скажу - просто блеск (не ИМХО, и вправду отличная IDE ).

И так, Qt и базы данных

Как уже неявно упомянулось выше, в Qt есть отдельный модуль, предоставляющий удобный «сервис» использования БД - QtSql . Если у вас есть опыт работы с Qt, то о файле.pro вам известно, если нет - познакомьтесь . Помните только, что нужно добавить следующую строку в.pro файл:
QT += sql
Это, чтоб использовать модуль QtSql, а для работы с ее классами, нужно включать одноименный заголовок.
#include
В книгах по Qt говорится о трех уровнях модуля QtSql:
  1. Уровень драйверов
  2. Программный уровень
Уровень драйверов
К уровню драйверов относятся классы для получения данных на физическом уровне, такие, как:
  • QSqlDriver
  • QSqlDriverCreator
  • QSqlDriverCreatorBase,
  • QSqlDriverPlugin
  • QSqlResult
QSqlDriver является абстрактным базовым классом, предназначенный для доступа к специфичным БД. Важно, что класс не должен быть использован «прямо», взамен нужно/можно воспользоваться QSqlDatabase . Хотя, если вы хотите создать свой собственный драйвер SQL, то можете наследовать от QSqlDriver и реализовать чисто виртуальные, и нужные вам виртуальные функции.
QSqlDriverCreator - шаблонный класс, предоставляющий фабрику SQL драйвера для специфичного типа драйвера. Шаблонный параметр должен быть подклассом QSqlDriver .
QSqlCreatorBase - базовый класс для фабрик SQL драйверов, чтобы возвращать экземпляр специфичного поскласса класса QSqlDriver , который вы хотите предоставить, нужно «перефразировать» метод createObject() .
QSqlDatabase несет ответственность за загрузку и управление плагинов драйверов баз данных. Когда база данных добавлена (это делается функцией QSqlDatabase::addDatabase() ), необходимый плагин драйвера загружается (используя QSqlDriverPlugin ). QSqlDriverPlugin предоставляет собой абстрактный базовый класс для пользовательских QSqlDriver плагинов.
QSqlResult сам говорит о себе (как и все Qt-шные классы), этот класс предоставляет абстрактный интерфейс для доступа к данным специфичных БД. С практической точки зрения мы будем использовать QSqlQuery вместо QSqlResult , поскольку QSqlQuery предоставляет обертку («обобщенную») для БД-специфичных реализации QSqlResult .
Так, поскольку уровень драйверов, как оказалось, актуально использовать при создании собственного драйвера, то привожу пример кода (для наиболее заинтересованных), который может быть использован как каркасс для драйвера:

Class XyzResult: public QSqlResult { public: XyzResult(const QSqlDriver *driver) : QSqlResult(driver) {} ~XyzResult() {} protected: QVariant data(int /* index */) { return QVariant(); } bool isNull(int /* index */) { return false; } bool reset(const QString & /* query */) { return false; } bool fetch(int /* index */) { return false; } bool fetchFirst() { return false; } bool fetchLast() { return false; } int size() { return 0; } int numRowsAffected() { return 0; } QSqlRecord record() const { return QSqlRecord(); } }; class XyzDriver: public QSqlDriver { public: XyzDriver() {} ~XyzDriver() {} bool hasFeature(DriverFeature /* feature */) const { return false; } bool open(const QString & /* db */, const QString & /* user */, const QString & /* password */, const QString & /* host */, int /* port */, const QString & /* options */) { return false; } void close() {} QSqlResult *createResult() const { return new XyzResult(this); } };

Программный уровень
Для соединения с базой данных прежде всего нужно активизировать драйвер используя статический метод QSqlDatabase::addDatabase() . Метод получает строку как аргумент, обозначающий идентификатор драйвер СУБД . Нам понадобится «QSQLITE».

QSqlDatabase sdb = QSqlDatabase::addDatabase("QSQLITE"); sdb.setDatabaseName("db_name.sqlite"); if (!sdb.open()) { //.... }
У статической функции addDatabase есть перегруженный «брат», получающий не имя драйвера, а сам драйвер(QSqlDriver *).
Соединение осуществляется методом open(). Класс QSqlDatabase представляет соединение с БД. Соединение предоставляет доступ к БД через поддерживаемый драйвер БД. Важно, что можно иметь несколько соединений к одной БД.
Если при соединении (метод open() ) возникла ошибка, то получить информацию об ошибке можно через метод QSqlDatabase::lastError() (возвращает QSqlError ).

If (!sdb.open()) { qDebug() << sdb.lastError().text(); }
Рассмотрим как Qt позволяет исполнять команды SQL. Для этого можно воспользоваться классом QSqlQuery . Класс может быть использована не только для исполнения DML (Data Manipulation Language) выражений, таких, как SELECT , INSERT , UPDATE и DELETE , но и DDL (Data Definition Language) выражений, таких, как CREATE TABLE . Обратите внимание, что может быть выполнена и БД-специфичная команда, не ялвяющийся стандартом SQL (например, для PSQL - «SET DATESTYLE=ISO»).
Удачно выполненные запросы устанавливают состояние запроса в «активный», так, isActive() возвратит true , в противоположном случае состояние устанавливается в неактивное. Запросы оформляются в виде обычной строки, которая передается в конструктор или в метод QSqlQuery::exec() . В первом случае, при передаче конструктору, запуск команды будет производиться автоматически (при конструировании объекта).
Что очень интересно, так это возможность навигации, предоставляемый QSqlQuery . Например, после запроса SELECT можно перемещаться по собранным данным при помощи методов next(), previous(), first(), last() и seek() .

QSqlQuery query("SELECT country FROM artist"); while (query.next()) { QString country = query.value(0).toString(); do_something(country); }
Метод next() позволяет перемащатся на следующую строку данных, а вызов previous() на предыдущую строку, соответственно. first(), last() извлекают, соответственно, первую запись из результата. seek() получает целочисленный индекс, извлекая запись из результата по полученному индексу и «позиционирует запрос» на извлеченную запись. Проверить размер, вернее количество строк данных (результата) можно методом size() . Важно помнить, что первая запись находится в позиции 0, запрос должен быть в активном состоянии, а isSelect () возвращать true (это происходит, если последним запросом был SELECT ) перед вызовом метода seek(). О методе seek () более подробно советую прочитать в официальной документации .
Выше упомянули, что если передавать строку запроса в конструктор класса QSqlQuery , то запрос выполнится при создании объекта - при конструировании. Используя метод exec () можно, так сказать, следить за временем выполнения запросов. Конструкция
QSqlQuery query("SELECT country FROM artist"); может быть представлена также так:
QSqlQuery query; query.exec("SELECT country FROM artist"); Так, exec () получает запрос в виде QString . Выполняя запрос, в случае удачи этот метод возвращает true и устанавливает состояние в активное, в противоположном случае все «противоположное» указанным операциям. Конечно, следует еще и помнить, что строка запроса должна подчиняться синтаксическим правилам запрашиваемой БД (в частности, стандарту SQL).
Что интересно, так после исполнения, запрос позиционируется на инвалидный(ую?) запись, то есть для адекватного использования результатов, необходимо воспользоваться, скажем, методом next ().
У метода exec () перегруженная альтернатива, не получающая никаких аргументов. Вызов этого варианта exec () исполняет до этого подготовленный запрос. Обратите внимание - «подготовленный». Для этого предназначен метод prepare (), который возвращает true в случае удачной подготовки запроса.
Важность или, можно сказать, уникальность метода в том, что запрос может содержать «заполнители» для связывания со значениями используая bindValue ().
QSqlQuery my_query; my_query.prepare("INSERT INTO my_table (number, address, age)" "VALUES (:number, :address, :age);"); my_query.bindValue(":number", "14"); my_query.bindValue(":address", "hello world str."); my_query.bindValue(":age", "37");
Еще можно использовать вариант безымянных параметров:

QSqlQuery my_query; my_query.prepare("INSERT INTO my_table (number, address, age)" "VALUES (?, ?, ?);"); my_query.bindValue("14"); my_query.bindValue("hello world str."); my_query.bindValue("37");
И наконец, можно просто использовать подставляемые аргументы, которые предоставляет QString:

QSqlQuery my_query; my_query.prepare(QString("INSERT INTO my_table (number, address, age) VALUES (%1, "%2", %3);") .arg("14").arg("hello world str.").arg("37"));
Компилируемый (copy-paste-to-your-ide) пример:

#include #include << "Что-то пошло не так!"; return -1; } QSqlQuery a_query; // DDL query QString str = "CREATE TABLE my_table (" "number integer PRIMARY KEY NOT NULL, " "address VARCHAR(255), " "age integer" ");"; bool b = a_query.exec(str); if (!b) { qDebug() << "Вроде не удается создать таблицу, провертье карманы!"; } // DML QString str_insert = "INSERT INTO my_table(number, address, age) " "VALUES (%1, "%2", %3);"; str = str_insert.arg("14") .arg("hello world str.") .arg("37"); b = a_query.exec(str); if (!b) { qDebug() << "Кажется данные не вставляются, проверьте дверь, может она закрыта?"; } //..... if (!a_query.exec("SELECT * FROM my_table")) { qDebug() << "Даже селект не получается, я пас."; return -2; } QSqlRecord rec = a_query.record(); int number = 0, age = 0; QString address = ""; while (a_query.next()) { number = a_query.value(rec.indexOf("number")).toInt(); age = a_query.value(rec.indexOf("age")).toInt(); address = a_query.value(rec.indexOf("address")).toString(); qDebug() << "number is " << number << ". age is " << age << ". address" << address; } return app.exec(); }
Для получения результата запроса следует вызвать метод QSqlQuery::value() , в котором необходимо передать номер столбца, для чего в примере воспользовались методом record (). Этот метод возвращает объект класса QSqlRecord , который содержит информацию, относящуюся к запросу SELECT . С помощью вызова QSqlRecord::indexOf() получаем индекс столбца.
Метод value() возвращает значения типа QVariant (класс, объекты которого могут содержать в себе значения разных типов), поэтому вы и преобразовали полученное значение, воспользовавшись методами QVariant::toInt() и QVariant::toString() .

Уровень пользовательского интерфейса
Модуль QtSql поддерживает концепцию «Интервью», предоставляя ряд моделей для использования их в представлениях. Чтобы хорошенько познакомиться с этой концепцией - загляните сюда .
В качестве примера, класс QSqlTableModel позволяет отображать данные в табличной и иерархической форме. Как утверждается в литературе, интервью - самый простой способ отобразить данные таблицы, здесь не потребуется цикла для прохождения по строкам таблицы. Вот малюсенький пример:

#include #include #include int main(int argc, char *argv) { QCoreApplication app(argc, argv); QSqlDatabase dbase = QSqlDatabase::addDatabase("QSQLITE"); dbase.setDatabaseName("my_db.sqlite"); if (!dbase.open()) { qDebug() << "Что-то не так с соединением!"; return -1; } QTableView view; QSqlTableModel model; model.setTable("my_table"); model.select(); model.setEditStrategy(QSqlTableModel::OnFieldChange); view.setModel(&model); view.show(); return app.exec(); }
После соединения создается объект табличного представления QTableView и объект табличной модели QSqlTableModel . Методом setTable () устанавливается актуальная база в модели, а вызов select () производит заполнение данными.
Класс QSqlTableModel предоставляет следующие стратегии редактирования (устанавливаемые с помощью setEditStrategy Добавить метки



© 2024 beasthackerz.ru - Браузеры. Аудио. Жесткий диск. Программы. Локальная сеть. Windows