web-dev-qa-db-ja.com

QSqlDatabaseとQSqlQueryの正しい方法は何ですか?

私はマニュアルと混同しました、私はこのように働くべきですか:

_{
 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()を呼び出さなかったとしても。

28
daisy

QSqlDatabaseaddDatabaseオブジェクトを作成するとき、またはremoveDatabaseを呼び出すときは、単にタプルを関連付けまたは関連付け解除します(driver、hostname:port、database name 、ユーザー名/パスワード)名前(または、接続名を指定しない場合はデフォルトの接続名)。
SQLドライバーはインスタンス化されますが、データベースは_QSqlDatabase::open_を呼び出したときにのみ開かれます。

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

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

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

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

  1. 単一のQSqlDatabaseインスタンスを単一のクラス(たとえばメインウィンドウ)に保持し、QSqlDatabaseを直接渡すか、接続名のみを渡すことで、それを必要とする他のオブジェクトで使用します。 _QSqlDatabase::database_に渡して、QSqlDatabaseインスタンスを取得します。 _QSqlDatabase::database_はQHashを使用してその名前からQSqlDatabaseを取得するため、QSqlDatabaseオブジェクトをオブジェクトと関数間で直接渡すよりもおそらく無視できるほど遅いです。デフォルトの接続を使用する場合、どこにも何も渡す必要はなく、パラメータなしでQSqlDatabase::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の接続も閉じられますが、これはおそらく悪いことです。

44
alexisdm

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

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

3
James Turner

命令は、以下の順序で正確に実行する必要があります。そうしないと、データベース接続またはクエリで問題が発生します。これは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";
}
0
Pescolly