Quelle est la bonne méthode de QSqlDatabase & QSqlQuery?
j'ai confondu avec le manuel , je devrais travailler comme ceci:
{
QSqlDatabase db = QSqlDatabase::addDatabase (...);
QSqlQuery query (db);
query.exec (...);
}
QSqlDatabase::removeDatabase (...);
Comme le document souligne, query
ou db
sera déconstruit automatiquement.
Mais est-ce efficace ?
Eh bien, si je cache db
à l'intérieur d'une classe , comme suit:
class Dummy {
Dummy() {
db = QSqlDatabase::addDatabase (...);
}
~Dummy() {
db.close();
}
bool run() {
QSqlQuery query (db);
bool retval = query.exec (...);
blabla ...
}
private:
QSqlDatabase db;
};
Parfois, je pouvais voir mises en garde de la forme:
QSqlDatabasePrivate::removeDatabase: connection 'BLABLA' is still in use, all queries will cease to work.
Même si je n'ai pas l'appeler run()
.
3 réponses
quand vous créez un QSqlDatabase
objet addDatabase
ou lorsque vous appelez removeDatabase
, vous êtes simplement à associer ou de dissociant d'un n-uplet (pilote, nom d'hôte:port, nom de base de données, nom d'utilisateur/mot de passe) à un nom (ou au nom de connexion par défaut si vous ne spécifiez pas de nom de connexion).
le pilote SQL est instancié, mais la base de données ne sera ouverte que lorsque vous appelez QSqlDatabase::open
.
ce nom de connexion est défini pour l'ensemble de l'application. Donc, si vous appelez addDatabase
dans chacun des objets qui l'utilisent, vous changez tout QSqlDatabase
objets qui utilisent le même nom de connexion et invalident toutes les requêtes qui étaient actives sur eux.
le premier exemple de code que vous avez cité montre comment dissocier correctement le nom de connexion, en s'assurant que:
QSqlQuery
sont détachés de l'QSqlDatabase
avant de fermer la base de données en appelantQSqlQuery::finish()
, qui est automatique lorsque leQSqlQuery
objet sort de portée,QSqlDatabase
avec le même nom de connexion sontclose()
d Quand vous appelezQSqlDatabase::removeDatabase
(close()
est aussi appelé automatiquement lorsque leQSqlDatabase
l'objet sort du champ d'application).
lorsque vous créez La base de données QSqlDatabase, selon que vous voulez que la connexion reste ouverte pendant toute la durée de vie de l'application (1) ou juste au besoin (2), vous pouvez:
un seul
QSqlDatabase
instance dans une seule classe (par exemple, dans votre mainwindow), et l'utiliser dans d'autres objets qui en ont besoin soit en passant leQSqlDatabase
directement ou tout simplement le nom de la connexion que vous passez àQSqlDatabase::database
pour obtenir l'QSqlDatabase
instance.QSqlDatabase::database
QHash
pour récupérer unQSqlDatabase
d'après son nom, il est donc probablement plus lent que de passer leQSqlDatabase
objet directement entre les objets et les fonctions, et si vous utilisez la connexion par défaut, vous n'avez même pas à passer quoi que ce soit n'importe où, il suffit d'appelerQSqlDatabase::database()
sans paramètre.// 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);
configurer le
QSqlDatabase
une fois, ouvrez - le pour vérifier que les paramètres sont corrects, et laissez tomber l'instance. Le nom de la connexion, sera toujours accessible n'importe où, mais la base de données devra être rouverte:{ // 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 }
dans ce cas, notez que vous ne devriez pas fermer la base de données explicitement, parce que vous pouvez avoir plusieurs objets utilisant la même connexion de base de données d'une manière rentrante (par exemple, si une fonction utilise connexion et appels B qui utilisent également la connexion. Si B ferme la connexion avant de retourner le contrôle à A, la connexion sera également fermée pour A, ce qui est probablement une mauvaise chose).
QSqlDatabase et QSqlQuery sont des enveloppements légers autour d'implémentations en béton, donc votre premier exemple est parfait. Si vous fournissez un nom lors de l'ajout de la connexion, ou utilisez la base de données par défaut, alors simplement en écrivant 'qsqldatabase db(name)' Vous donne l'objet de base de données avec très peu de frais généraux.
removeDatabase est équivalent à fermer le fichier (pour sqlite) ou la connexion (pour ODBC/MySql/Postgres), donc c'est typiquement quelque chose que vous feriez à la fin du programme. Comme l'avertissement dit, vous devez vous assurer que tous les objets de base de données et de requête qui se réfèrent à cette base de données, ont déjà été détruits, ou de mauvaises choses peuvent se produire.
je trouve que les instructions doivent être exécutées exactement dans l'ordre où elles se trouvent ci-dessous ou bien vous avez des problèmes, soit avec la connexion à la base de données, soit avec la requête. Cela fonctionne en 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";
}