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

时间:2011-10-06 03:14:00

标签: database qt qt4 qtsql

我对手册感到困惑,如果我这样工作:

{
 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()

3 个答案:

答案 0 :(得分:42)

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

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

您引用的第一个代码示例显示了如何通过确保:

正确取消关联连接名称
  • 所有QSqlQuery都会在关闭数据库之前与QSqlDatabase分离,方法是调用QSqlQuery::finish(),这在QSqlQuery对象超出范围时是自动的,
  • 当你致电QSqlDatabase时,{li>具有相同连接名称的所有close() QSqlDatabase::removeDatabase d close()QSqlDatabase对象退出时,QSqlDatabase也会自动调用QSqlDatabase范围)。

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

  1. 在一个单独的类中保留一个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); 对象慢得多,如果您使用默认连接,您甚至不必在任何地方传递任何内容,只需在没有任何参数的情况下调用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
    } 
    
  2. 配置{{1}}一次,打开它以测试参数是否正确,然后抛弃实例。连接名称仍可在任何地方访问,但必须重新打开数据库:

    {{1}}

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

答案 1 :(得分:3)

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

removeDatabase相当于关闭文件(对于sqlite)或连接(对于ODBC / MySql / Postgres),因此通常是在程序终止时执行的操作。如警告所示,您必须确保所有引用该数据库的数据库和查询对象已被破坏,或者可能发生不良事件。

答案 2 :(得分: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";
}