Russian Qt Forum

Qt => Базы данных => Тема начата: Павелъ от Декабрь 07, 2017, 13:23



Название: Как грамотно закрыть подключение к БД?
Отправлено: Павелъ от Декабрь 07, 2017, 13:23
Доброго времени суток.

Понадобилось написать функцию, которая проверяет доступность БД.

Есть три СУБД: на Оракле, на ПосгреСКЛ и на МССКЛ.

Функция, возвращающая конечный результат:

Код:
bool CommonFunctions::isConnectedToDataBase(DataBaseInfo dbInfo)
{
    switch (dbInfo.dbType) {
    case dbOracle:
        return isConnectToOracleDataBase(dbInfo);
    case dbMSSQL:
        return isConnectedToMS_SQL_dataBase(dbInfo);
    case dbPosgreSQL:
        return isConnectedToPosgreSQL_dataBase(dbInfo);
    }
    return false;
}


Для Оракле:

Код:
bool CommonFunctions::isConnectToOracleDataBase(DataBaseInfo dbInfo)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QOCI","Oracle_connection");
    db.setDatabaseName(dbInfo.dataBaseName);
    db.setHostName(dbInfo.ipAddress);
    db.setPort(dbInfo.port);
    db.setUserName(dbInfo.userName);
    db.setPassword(dbInfo.password);

    if(!db.open())
    {
        db.removeDatabase("Oracle_connection");
        return false;
    }

    QSqlQuery query(db);

    query.exec("select * from v$version");

    bool retBool = false;

    if(!query.lastError().type())
    {
        retBool = query.first();
    }

    if(db.isOpen())
    {
        db.close();
    }

    db.removeDatabase("Oracle_connection");

    return retBool;
}

Для МССКЛ:

Код:
bool CommonFunctions::isConnectedToMS_SQL_dataBase(DataBaseInfo dbInfo)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC3","MS_SQL_connection");

    db.setDatabaseName(getODBCconnectionSettings(dbInfo));

    if(!db.open())
    {
        db.removeDatabase("MS_SQL_connection");
        return false;
    }

    QSqlQuery query(db);

    query.exec("select @@version");

    bool retBool = false;

    if(!query.lastError().type())
    {
        retBool = query.first();
    }

    if(db.isOpen())
    {
        db.close();
    }

    db.removeDatabase("MS_SQL_connection");

    return retBool;
}

Для Посгре:

Код:
bool CommonFunctions::isConnectedToPosgreSQL_dataBase(DataBaseInfo dbInfo)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL","PosgreSQL_connection");
    db.setDatabaseName(dbInfo.dataBaseName);
    db.setHostName(dbInfo.ipAddress);
    db.setPort(dbInfo.port);
    db.setUserName(dbInfo.userName);
    db.setPassword(dbInfo.password);

    if(!db.open())
    {
        db.removeDatabase("PosgreSQL_connection");
        return false;
    }

    QSqlQuery query(db);

    query.exec("select version()");

    bool retBool = false;

    if(!query.lastError().type())
    {
        retBool = query.first();
    }

    if(db.isOpen())
    {
        db.close();
    }

    db.removeDatabase("PosgreSQL_connection");

    return retBool;
}

Ну, и вспомогательная функция для соединения с QODBC:

Код:
QString CommonFunctions::getODBCconnectionSettings(DataBaseInfo dbInfo)
{
    return "DRIVER={SQL Server};Server=" + dbInfo.ipAddress + "," + QString::number(dbInfo.port) +";Database=" + dbInfo.dataBaseName + ";Uid=" + dbInfo.userName + ";Pwd=" + dbInfo.password + ";WSID=.";
}



Сначала я создавал подключение к БД таким образом:

Код:
QSqlDatabase db = QSqlDatabase::addDatabase("QOCI");

Но после вызова следующей функции появлялись варнинги о том, что старое соединение удалено, хотя перед возвращением результата я делаю db.close().

Тогда я прочитал, что надо в таком случае указать имя соединения, и я сделал подключение следующим образом:

Код:
QSqlDatabase db = QSqlDatabase::addDatabase("QOCI","Oracle_connection");

добавив имя соединения.

С тремя разными соединениями это прокатывает, но как только я вызываю ещё раз проверку соединения, например для Оракла, то опять появляется сообщение, что старое соединение удалено.

Тогда я решил, что после db.close() сделаю следующее:

Код:
db.removeDatabase("Oracle_connection");

И тут начались варнинги с вылетами приложения:

Код:
QSqlDatabasePrivate::removeDatabase: connection 'MS_SQL_connection' is still in use, all queries will cease to work.


Вопрос в следующем. Есть данные для подключения к БД.
Мне нужно получить ТОЛЬКО информацию о том, есть ли подключение и посылается ли тестовый sql-запрос.
То есть, в функции создаётся соединение, а перед тем, как возвратить результат оно должно полностью закрыться и удалиться из программы.

То есть: есть данные для БД, нужно возвратить её работоспособность и не хранить никаких соединений.

Что я делаю не так, и как это грамотно сделать?

Спасибо.


Название: Re: Как грамотно закрыть подключение к БД?
Отправлено: Павелъ от Декабрь 07, 2017, 14:23
Пришла идея проверять наличие соединения с помощью contains а qsqldatabase. При наличии делать соединение к существующей, иначе - создавать.


Название: Re: Как грамотно закрыть подключение к БД?
Отправлено: Павелъ от Декабрь 07, 2017, 17:50
Да, так работает.