我对手册感到困惑,如果我这样工作:
{
QSqlDatabase db = QSqlDatabase::addDatabase (...);
QSqlQuery query (db);
query.exec (...);
}
QSqlDatabase::removeDatabase (...);
正如文件指出的那样,query
或db
将被自动解构。
但这有效吗?
好吧,如果我在一个类中缓存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()
。
答案 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),您可以:
在一个单独的类中保留一个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
}
配置{{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";
}