【问题标题】:What is the correct way of QSqlDatabase & QSqlQuery?QSqlDatabase & QSqlQuery 的正确方法是什么?
【发布时间】:2011-12-01 23:15:42
【问题描述】:

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

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

QSqlDatabase::removeDatabase (...);

正如文档指出的那样,querydb 将被自动解构。 但是这样有效率吗?

好吧,如果我在一个类中缓存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()

【问题讨论】:

    标签: database qt qt4 qtsql


    【解决方案1】:

    当您使用addDatabase 创建QSqlDatabase 对象或调用removeDatabase 时,您只是关联或取消关联元组(驱动程序、主机名:端口、数据库名称、用户名/密码) em> 到一个名称(或默认连接名称,如果您不指定连接名称)。
    SQL驱动被实例化了,但是只有调用QSqlDatabase::open才会打开数据库。

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

    您引用的第一个代码示例显示了如何正确解除连接名称的关联,方法是确保:

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

    创建 QSqlDatabase 时,取决于您是希望连接在应用程序生命周期内保持打开状态 (1) 还是仅在需要时 (2),您可以:

    1. 在一个类中保留一个 QSqlDatabase 实例(例如,在您的主窗口中),并通过直接传递 QSqlDatabase 或仅传递给 @ 的连接名称在需要它的其他对象中使用它987654338@ 获取 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 关闭,这可能是一件坏事。

    【讨论】:

    • 我遇到了这个问题,在进行此调整后,我能够关闭数据库调用QSqlDatabase::removeDatabase(QSqlDatabase::database("DATABASE NAME");
    【解决方案2】:

    QSqlDatabase 和 QSqlQuery 是围绕具体实现的轻量级包装器,因此您的第一个示例很好。如果您在添加连接时提供了名称,或者使用默认数据库,那么只需编写“QSqlDatabase db(name)”即可为您提供数据库对象的开销非常小。

    removeDatabase 相当于关闭文件(对于 sqlite)或连接(对于 ODBC/MySql/Postgres),所以这通常是您在程序终止时会做的事情。正如警告所说,您必须确保所有引用该数据库的数据库和查询对象都已被销毁,否则可能会发生坏事。

    【讨论】:

      【解决方案3】:

      我发现指令必须完全按照下面的顺序运行,否则您会遇到问题,无论是数据库连接还是查询。这在 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";
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多