QSqlDatabase & QSqlQuery的正确方式是什么?[英] What is the correct way of QSqlDatabase & QSqlQuery?

本文是小编为大家收集整理的关于QSqlDatabase & QSqlQuery的正确方式是什么?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

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

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

QSqlDatabase::removeDatabase (...);

正如文档指出的那样,query或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().

推荐答案

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

时才会打开数据库.

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

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

正确解除连接名称
  • 所有QSqlQuery在通过调用QSqlQuery::finish()关闭数据库之前将其分离为QSqlDatabase,当QSqlQuery::finish() QSqlQuery::finish() QSqlQuery::finish() 对象脱离范围时,
  • 所有QSqlDatabase带有相同连接名称的所有close() d当您调用QSqlDatabase::removeDatabase时(close()当close() QSqlDatabase QSqlDatabase对象都超出范围时).

创建QSQLDATABASE时,取决于您是否希望连接在应用程序寿命(1)或仅在需要时(2)时保持开放,可以:

  1. 将单个QSqlDatabase实例保留在一个单个类中(例如,在您的MainWindow中),并将其用于其他对象,可以通过直接传递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使用a使用连接并调用B连接.如果b在将控件返回到A之前关闭连接,则该连接也将关闭A,这可能是一件坏事).

其他推荐答案

qsqldatabase和qsqlquery是混凝土实现的轻量级包装器,因此您的第一个示例很好.如果在添加连接时提供名称或使用默认数据库,则简单地编写" QSQLDATABASE DB(名称)"为您提供了很少的开销数据库对象.

删除数据库等效于关闭文件(对于SQLITE)或连接(对于ODBC/MySQL/Postgres),因此通常您会在程序终止时要做的事情.如警告所述,您必须确保所有指向该数据库,已经被销毁或可能发生坏事的数据库和查询对象.

其他推荐答案

我发现必须按以下顺序按以下顺序运行指令,否则您对数据库连接或查询有问题.这在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";
}

本文地址:https://www.itbaoku.cn/post/597424.html

问题描述

I got confused with the manual , should i work like this:

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

QSqlDatabase::removeDatabase (...);

As the document points out, query or db will be deconstructed automatically. But is that efficient ?

Well , if i cache db inside a class , like the following:

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

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

  private:
    QSqlDatabase db;
};

Sometimes i could see warnings like:

QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work.

Even if i didn't call run().

推荐答案

When you create a QSqlDatabase object with addDatabase or when you call removeDatabase, you are merely associating or disassociating a tuple (driver, hostname:port, database name, username/password) to a name (or to the default connection name if you don't specify a connection name).
The SQL driver is instantiated, but the database will only be opened when you call QSqlDatabase::open.

That connection name is defined application-wide. So if you call addDatabase in each of the objects that use it, you are changing all QSqlDatabase objects that uses the same connection name and invalidating all queries that were active on them.

The first code example you cited shows how to correctly disassociate the connection name, by ensuring that:

  • all QSqlQuery are detached from the QSqlDatabase before closing the database by calling QSqlQuery::finish(), which is automatic when the QSqlQuery object goes out of scope,
  • all QSqlDatabase with the same connection name are close()d when you call QSqlDatabase::removeDatabase (close() is also called automatically when the QSqlDatabase object goes out of scope).

When you create the QSqlDatabase, depending on whether you want the connection to stay open for the application lifetime (1) or just when needed (2), you can:

  1. keep a single QSqlDatabase instance in one single class (for example, in your mainwindow), and use it in other objects that needs it either by passing the QSqlDatabase directly or just the connection name that you pass to QSqlDatabase::database to get the QSqlDatabase instance back. QSqlDatabase::database uses QHash to retrieve a QSqlDatabase from its name, so it is probably negligibly slower than passing the QSqlDatabase object directly between objects and functions, and if you you use the default connection, you don't even have to pass anything anywhere, just call QSqlDatabase::database() without any parameter.

    // 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. configure the QSqlDatabase once, open it to test that the parameters are correct, and ditch the instance. The connection name, will still be accessible anywhere, but the database will have to be reopened:

    {
        // 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
    } 
    

    In that case, note that you shouldn't close the database explicitly, because you can have multiple objects using the same database connection in a reentrant manner (for example, if a function A use the connection and calls B which also use the connection. If B closes the connection before returning control to A, the connection will also be closed for A, which is probably a bad thing).

其他推荐答案

QSqlDatabase and QSqlQuery are lightweight wrappers around concrete implementations, so your first example is fine. If you provide a name when adding the connection, or use the default database, then simply writing 'QSqlDatabase db(name)' gives you the database object with very little overhead.

removeDatabase is equivalent to closing the file (for sqlite) or the connection (for ODBC/MySql/Postgres), so that's typically something you would do at program termination. As the warning says, you must ensure all database and query objects which refer to that database, have already been destroyed, or bad things can happen.

其他推荐答案

I find that the instructions have to be run exactly in the order it is below or else you have issues, either with the database connection or query. This works in 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";
}