QSqlDatabase和QSqlQuery的正确方法是什么?

dai*_*isy 29 database qt qt4 qtsql

我对手册感到困惑,我应该像这样工作:

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

QSqlDatabase::removeDatabase (...);
Run Code Online (Sandbox Code Playgroud)

正如文件所指出的,querydb将被自动解构.但这有效吗?

好吧,如果我db在一个类中缓存,如下所示:

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

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

  private:
    QSqlDatabase db;
};
Run Code Online (Sandbox Code Playgroud)

有时我会看到警告:

QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work.
Run Code Online (Sandbox Code Playgroud)

即使我没有打电话run().

ale*_*sdm 46

QSqlDatabase使用addDatabase或在调用时创建对象时removeDatabase,只是将元组(驱动程序,主机名:端口,数据库名称,用户名/密码)与名称关联或取消关联(如果未指定,则为默认连接名称)连接名称).
SQL驱动程序已实例化,但只有在调用时才会打开数据库QSqlDatabase::open.

该连接名称是在应用程序范围内定义的.因此,如果您调用addDatabase每个使用它的对象,您将更改QSqlDatabase使用相同连接名称的所有对象,并使所有对它们有效的查询无效.

您引用的第一个代码示例显示了如何正确地取消关联连接名称,确保:

  • 所有QSqlQuery都是QSqlDatabase通过调用关闭数据库之前分离的QSqlQuery::finish(),当QSqlQuery对象超出范围时,这是自动的,
  • 当你调用时,所有QSqlDatabase具有相同连接名称的都是close()d QSqlDatabase::removeDatabase(close()QSqlDatabase对象超出范围时也会自动调用).

创建QSqlDatabase时,根据您是希望连接在应用程序生存期(1)或仅在需要时(2)保持打开,您可以:

  1. 将单个QSqlDatabase实例保存在一个单独的类中(例如,在主窗口中),并在需要它的其他对象中使用它,方法是QSqlDatabase直接传递或只传递传递给的连接名称QSqlDatabase::database以获取QSqlDatabase实例.QSqlDatabase::database用于从其名称中QHash检索a 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);             
    
    Run Code Online (Sandbox Code Playgroud)
  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
    } 
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,请注意您不应显式关闭数据库,因为您可以以可重入的方式使用相同的数据库连接(例如,如果函数A使用连接并调用也使用该连接的B).如果B在将控制权返回给A之前关闭了连接,那么A的连接也将被关闭,这可能是一件坏事.