Программирование на C++ с использованием библиотеки Qt4

Подключение с базе данных и выполнение SQL-запросов


Для подключения к базе данных надо указать название SQL-драйвера, например: QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "MyDB1"); Второй необязательный параметр позволяет задать имя соединения.

Затем указывается имя сервера, название базы данных, имя пользователя и пароль: db.setHostName("localhost"); // или, например, "my1.server.ru" db.setDatabaseName("mydb1"); db.setUserName("root"); db.setPassword("mypassword"); Если сервер использует нестандартный порт, то придётся задать и его: db.setPort(НомерПорта); В случае использования QODBC имя сервера не требуется, а вместо названия базы данных указывается ODBC-псевдоним (алиас).

SQLite не поддерживает авторизацию пользователей, поэтому ему требуется указать только имя файла данных. Предопределённое имя ":memory:" позволяет размещать временную базу данных в оперативной памяти.

После того, как все параметры подключения заданы, можно открыть соединение: bool connected = db.open(); Если подключение установить не удалось, то не плохо бы узнать описание ошибки и сообщить его пользователю: if (!connected) { QMessageBox::critical( // Диалог с сообщением об ошибке. parent, // Родительский виджет. QObject::tr("Database Error"), // Заголовок. db.lastError().text()); // Текст сообщения. return false; // Вернуть признак неудачного подключения. } Если подключение установлено, то можно выполнить любой SQL-запрос, например: QSqlQuery sql; sql.exec("SELECT id, name, salary FROM empl WHERE salary>=1000"); или QSqlQuery sql("SELECT id, name, salary FROM empl WHERE salary>=1000"); Здесь запрашиваются номера id, имена name и оклады salary всех работников из таблицы empl, у которых оклад не ниже 1000. Обратите внимание, что если при создании объекта QSqlQuery указан текст запроса на языке SQL, то этот запрос сразу выполняется.

В обоих случаях в конструкторе запроса можно указать базу данных QSqlDatabase, с которой он будет работать. Но как правило, приложение открывает только одно соединение с единственной базой данных, поэтому этот параметр принимает значение по умолчанию.

Если при выполнении запроса возникла ошибка, то метод lastError() позволяет вывести на экран её описание: if ( ! query.isActive() ) QMessageBox::warning( this, tr("Database Error"), query.lastError().text() ); Иначе можно получить данные, которые сервер вернул в качестве результата: while ( sql.next() ) { qint64 id = sql.value(0).toLongLong(); QString name = sql.value(1).toString(); double salary = sql.value(2).toDouble(); // ....... } Метод QSqlQuery::next() переводит курсор на очередную запись результирующего набора данных или возвращает false, если достигнут его конец. Метод value(номер_столбца) возвращает значение типа QVariant, которое надо преобразовать к нужному типу с помощью методов QVariant::toInt, QVariant::toLongLong, QVariant::toString, QVariant::toDouble, QVariant::toDate, QVariant::toDateTime и т.д.

Кроме next(), для навигации по набору данных можно использовать методы first(), last(), previous(), seek(int index, bool relative=false). Для увеличения быстродействия набор данных лучше сделать однонаправленным, вызвав метод QSqlQuery::setForwardOnly(true) до выполнения запроса, после этого можно использовать только next().

Метод QSqlQuery::size() возвращает число записей, полученных в результате выполнения запроса SELECT (-1, если была ошибка или если драйвер данной СУБД не поддерживает эту функцию). При выполнении SQL-запросов INSERT, UPDATE или DELETE вместо size() надо использовать метод QSqlQuery::numRowsAffected(). Чтобы узнать, возникла ли ошибка при последнем выполнении запроса, используется метод QSqlQuery::lastError(). Аналогичный метод имеет и класс QSqlDatabase. В обоих случаях возвращается экземпляр класса QSqlError. Тип ошибки можно выяснить, вызвав метод QSqlError::type(). Возможные типы ошибок: QSqlError::NoError (ошибок не было), QSqlError::ConnectionError (ошибка соединения), QSqlError::StatementError (синтаксическая ошибка в SQL-запросе), QSqlError::TransactionError (ошибка транзакции) и QSqlError::UnknownError (неизвестная ошибка).

Если требуется выполнить большое количество однотипных SQL-операторов, то эффективнее использовать запрос с параметрами: QSqlQuery query; sql.prepare("INSERT INTO empl (id, name, salary) " "VALUES (:id, :name, :salary)"); for (int i=0; i<N; i++) { sql.bindValue(":id", arr_id[i]); sql.bindValue(":name", arr_name[i]); sql.bindValue(":salary", arr_salary[i]); sql.exec(); } или, что же самое (только параметры безымянные): QSqlQuery query; sql.prepare("INSERT INTO empl (id, name, salary) " "VALUES (?, ?, ?)"); for (int i=0; i<N; i++) { sql.addBindValue(arr_id[i]); sql.addBindValue(arr_name[i]); sql.addBindValue(arr_salary[i]); sql.exec(); } Здесь выполняется вставка N записей, данные берутся из массивов arr_id, arr_name и arr_salary.

Если СУБД поддерживает механизм транзакций, то для начала новой транзакции используется метод bool QSqlDatabase::transaction() для её подтверждения надо вызвать bool QSqlDatabase::commit() а для отмены: bool QSqlDatabase::rollback() Если СУБД не поддерживает транзакций, то вызовы transaction, commit и rollback ничего не делают. С помощью метода QSqlDriver::hasFeature() можно узнать, поддерживается ли данным драйвером и СУБД та или иная функция, в том числе и транзакции: QSqlDriver *driver = QSqlDatabase::database().driver(); if (driver->hasFeature(QSqlDriver::Transactions)) ....... Каждое соединение с базой данных может иметь только одну активную транзакцию. Если этого недостаточно, всегда можно открыть ещё несколько соединений с той же базой данных.

Ссылку на соединение с базой данных можно получить, вызвав функцию QSqlDatabase::database(connectionName). Необязательный параметр connectionName -- это имя соединения, которое было задано при его создании с помощью QSqlDatabase::addDatabase().

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


Выполнение SQL-запросов (система Windows, драйвер QODBC)


Выполнение SQL-запросов (система Linux, драйвер QMYSQL)

В листингах приведён пример программы, работающей с базой данных, а на рис. показан результат её работы в Windows и Linux.



Содержание раздела