首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QSqlDatabase和QSqlQuery的正确方式是什么?

QSqlDatabase和QSqlQuery的正确方式是什么?
EN

Stack Overflow用户
提问于 2011-10-06 11:14:00
回答 3查看 48.2K关注 0票数 30

我把手册搞混了,我是不是应该这样工作:

代码语言:javascript
复制
{
 QSqlDatabase db = QSqlDatabase::addDatabase (...);
 QSqlQuery query (db);
 query.exec (...);
}

QSqlDatabase::removeDatabase (...);

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

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

代码语言:javascript
复制
class Dummy {
  Dummy() { 
    db = QSqlDatabase::addDatabase (...);
  }
  ~Dummy() {
    db.close();
  }

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

  private:
    QSqlDatabase db;
};

有时我会看到这样的警告:

代码语言:javascript
复制
QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work.

即使我没有给run()打电话。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-07 23:38:16

当您使用addDatabase创建QSqlDatabase对象或调用removeDatabase时,您只是将一个元组(驱动程序、主机名:端口、数据库名、用户名/密码)关联或解除关联到一个名称(如果不指定连接名称,则关联到默认连接名称)。

SQL驱动程序已实例化,但只有在调用QSqlDatabase::open时才会打开数据库。

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

您引用的第一个代码示例显示了如何通过确保以下内容正确取消连接名称的关联:

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

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

  1. 将单个QSqlDatabase实例保存在单个类中(例如,在主窗口中),并在需要它的其他对象中使用它,方法是直接传递QSqlDatabase或仅传递给QSqlDatabase::database的连接名称以获取QSqlDatabase实例。QSqlDatabase::database使用QHash从其名称中检索QSqlDatabase,因此它可能比直接在对象和函数之间传递QSqlDatabase对象慢得可以忽略不计,而且如果您使用默认连接,您甚至不必传递任何东西,只需在不带任何参数的情况下调用QSqlDatabase::database()

//在与应用程序具有相同生命周期的对象中// (或者作为全局变量,因为它在这里具有几乎相同的目标)QSQLDRIVER db;//在该对象的构造函数或初始化函数中QSqlDatabase db =QSQLDRIVER::addDatabase(“QSQLDRIVER”,"connection-name");db.setHostname( ... );// ...if(!this->db.open()) //打开并保持打开{ //错误处理...} // - //在您需要的任何地方,都可以使用“全局”db对象//或者从连接名QSqlDatabase db = QSqlDatabase:: database (" connection - name ");QSqlQuery query(db);

  • 配置一次QSqlDatabase,打开测试参数是否正确,然后丢弃实例。仍然可以在任何位置访问连接名称,但必须重新打开数据库:

{ //堆栈上分配的QSqlDatabase db = QSqlDatabase::addDatabase("QSQLDRIVER","connection-name");db.setHostname( ... );// ...如果(!this->db.open()) //测试连接{ //错误处理} // db超出作用域时关闭}{ //与(1)相同,但默认情况下,数据库()打开//连接(如果尚未打开) QSqlDatabase db = QSqlDatabase::database(" connection -name");QSqlQuery query(db);//如果没有打开该连接名称的其他连接,//当db超出作用域时,该连接将关闭}

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

票数 46
EN

Stack Overflow用户

发布于 2011-10-07 02:05:35

QSqlDatabase和QSqlQuery是具体实现的轻量级包装器,因此您的第一个示例就可以了。如果您在添加连接时提供名称,或者使用默认数据库,则只需编写'QSqlDatabase db( name )‘即可获得开销很小的数据库对象。

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

票数 4
EN

Stack Overflow用户

发布于 2013-09-14 14:19:09

我发现这些指令必须完全按照下面的顺序运行,否则您就会遇到数据库连接或查询方面的问题。这在Qt5中有效。

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7669987

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档