30

マニュアルと混同しました。次のように作業する必要があります。

{
 QSqlDatabase db = QSqlDatabase::addDatabase (...);
 QSqlQuery query (db);
 query.exec (...);
}

QSqlDatabase::removeDatabase (...);

ドキュメントが指摘するように、queryまたはdb自動的に分解されます。しかし、それは効率的ですか?

さて、db次のように、クラス内にキャッシュすると:

class Dummy {
  Dummy() { 
    db = QSqlDatabase::addDatabase (...);
  }
  ~Dummy() {
    db.close();
  }

  bool run() {
    QSqlQuery query (db);
    bool retval = query.exec (...);
    blabla ...
  }

  private:
    QSqlDatabase db;
};

時々、次のような警告が表示されることがあります。

QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work.

私が電話しなくてもrun()

4

3 に答える 3

46

QSqlDatabaseを使用してオブジェクトを作成するとき、addDatabaseまたは を呼び出すときremoveDatabaseは、タプル(ドライバー、ホスト名:ポート、データベース名、ユーザー名/パスワード)を名前 (または、指定しない場合はデフォルトの接続名) に関連付けるか、関連付けを解除するだけです。接続名)。
SQL ドライバーはインスタンス化されますが、データベースは を呼び出したときにのみ開かれますQSqlDatabase::open

その接続名は、アプリケーション全体で定義されます。したがって、addDatabaseそれを使用する各オブジェクトを呼び出すと、同じ接続名を使用するすべてのQSqlDatabaseオブジェクトが変更され、それらに対してアクティブだったすべてのクエリが無効になります。

引用した最初のコード例は、次のことを確認して、接続名の関連付けを正しく解除する方法を示しています。

  • を呼び出してデータベースを閉じる前に、すべてQSqlQueryが から切り離されます。これは、オブジェクトがスコープ外になると自動的に行われます。QSqlDatabaseQSqlQuery::finish()QSqlQuery
  • QSqlDatabase同じ接続名を持つものはすべて、close()呼び出し時に d になりますQSqlDatabase::removeDatabase(オブジェクトがスコープ外にclose()なると、 も自動的に呼び出されます)。QSqlDatabase

QSqlDatabase を作成するとき、接続をアプリケーションの存続期間中 (1) または必要なときだけ (2) 開いたままにするかどうかに応じて、次のことができます。

  1. 1つのインスタンスを 1 つのクラス (メインウィンドウなど) に保持し、インスタンスを取得するために渡す接続名を直接または単にQSqlDatabase渡すことによって、それを必要とする他のオブジェクトで使用します。を使用してその名前から a を取得するため、オブジェクトと関数の間でオブジェクトを直接渡すよりもおそらく無視できるほど遅くなります。デフォルトの接続を使用する場合は、どこにも何も渡す必要はなく、パラメーターなしで呼び出すだけです。QSqlDatabaseQSqlDatabase::databaseQSqlDatabaseQSqlDatabase::databaseQHashQSqlDatabaseQSqlDatabaseQSqlDatabase::database()

    // In an object that has the same lifetime as your application
    // (or as a global variable, since it has almost the same goal here)
    QSqlDatabase db;
    
    // In the constructor or initialization function of that object       
    db = QSqlDatabase::addDatabase("QSQLDRIVER", "connection-name"); 
    db.setHostname(...);
    // ...
    if(!this->db.open())  // open it and keep it opened
    {
        // Error handling...
    }
    
    // --------
    // Anywhere you need it, you can use the "global" db object 
    // or get the database connection from the connection name        
    QSqlDatabase db = QSqlDatabase::database("connection-name"); 
    QSqlQuery query(db);             
    
  2. 一度構成し、QSqlDatabaseそれを開いてパラメーターが正しいことをテストし、インスタンスを破棄します。接続名はどこからでもアクセスできますが、データベースを再度開く必要があります。

    {
        // Allocated on the stack
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLDRIVER", "connection-name"); 
        db.setHostname(...);
        // ...
        if(!this->db.open()) // test the connection
        {
           // Error handling
        }
    // db is closed when it goes out of scope
    } 
    
    {
        // Same thing as for (1), but by default database() opens 
        // the connection if it isn't already opened 
        QSqlDatabase db = QSqlDatabase::database("connection-name"); 
        QSqlQuery query(db);
    
    // if there is no other connection open with that connection name,
    // the connection is closed when db goes out of scope
    } 
    

    その場合、再入可能な方法で同じデータベース接続を使用する複数のオブジェクトを持つことができるため、データベースを明示的に閉じるべきではないことに注意してください (たとえば、関数 A が接続を使用し、接続も使用する B を呼び出す場合)。 B が A に制御を返す前に接続を閉じると、A の接続も閉じられますが、これはおそらく悪いことです)。

于 2011-10-07T15:38:15.640 に答える
4

QSqlDatabase と QSqlQuery は具体的な実装の軽量ラッパーであるため、最初の例は問題ありません。接続を追加するときに名前を指定するか、デフォルトのデータベースを使用する場合は、'QSqlDatabase db(name)' と記述するだけで、データベース オブジェクトのオーバーヘッドがほとんどなくなります。

removeDatabase は、ファイル (sqlite の場合) または接続 (ODBC/MySql/Postgres の場合) を閉じることと同等であるため、これは通常、プログラムの終了時に行うことです。警告が示すように、そのデータベースを参照するすべてのデータベースおよびクエリ オブジェクトが既に破棄されていることを確認する必要があります。そうしないと、問題が発生する可能性があります。

于 2011-10-06T18:05:35.330 に答える
0

手順は、以下の順序で正確に実行する必要があることがわかりました。そうしないと、データベース接続またはクエリで問題が発生します。これはQt5で動作します。

QSqlQueryModel *model = new QSqlQueryModel;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(fileName);

if (db.isValid())
{
    db.open();
    if (db.isOpen())
    {
        QSqlQuery searchQuery(db);
        searchQuery.prepare("SELECT * FROM myTable");
        searchQuery.exec();
        if(searchQuery.isActive())
        {
            model->setQuery(searchQuery);
            sui->DBDisplay->setModel(model);
            db.close();
        } else {
            qDebug() << "query is not active";
        }
    } else {
        qDebug() << "DB is not open";
    }
} else {
    qDebug() << "DB is not valid";
}
于 2013-09-14T06:19:09.213 に答える