PDA

View Full Version : Removing database connections



Matt31415
2nd July 2010, 20:38
I ran into an interesting problem today, and although I seem to have fixed it, I'm not totally sure that my fix was a good one.

First, some background. My program is a multi-threaded server that requires database access from each each thread. Because QSqlDatabase objects can't use the same connection from different threads (per the docs), I generate a new connection (with a unique name) in each thread. Since I don't want to have a prgoram with a million unused connections, I was deleting the connection when the thread ended. This was where my problems started. Deleting the connection resulted in a "connection still in use warning"

Here is what my original code looked like:



class configDb
class configDb
{
public:
configDb();
~configDb();
private:
QSqlDatabase configDb_;
};

void configDb::configDb()
{
QString connectionName = "connection"+QString::number(rand());
configDb_ = QSqlDatabase::addDatabase("QSQLITE",connectionName_);
configDb_.setDatabaseName(QCoreApplication::applic ationDirPath() + "/PictoServer.config");
configDb_.open();
}

void configDb::~configDb()
{
configDb_.close();

//WARNING occurs here:
QSqlDatabase::removeDatabase(configDb_.connectionN ame());
}


My first assumption was that I had somehow left an open query, but that wasn't possible since the queries were all in separate functions and were defined locally (and hence were deleted before the destructor was called).

After banging my head against the wall for a bit, I realized that I can't call removeDatabase while the configDb_ object still exists. Since it's a class member, I can't figure out an easy way to destruct it (delete doesn't work on a non-pointer, and I can't wait to call the class destructor until after the class itself is deleted).

So, to fix all of this, I am using pointers (since you can call delete on a pointer):



class configDb
{
public:
configDb();
~configDb();
private:
QSqlDatabase *configDb_;
QString connectionName_;
};

void configDb::configDb()
{
connectionName_ = "connection"+QString::number(rand());
configDb_ = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE",connectionName_));
configDb_->setDatabaseName(QCoreApplication::applicationDirPa th() + "/PictoServer.config");
configDb_->open();
}

void configDb::~configDb()
{
configDb_->close();
delete configDb_;

QSqlDatabase::removeDatabase(connectionName_);
}


The above code fixes my problem, but it seems like a total hack. This makes me worried that I have misunderstood something really fundamental, either about QSqlDatabase, or (even more embarassing) the destruction of objects in C++.

I suspect that someone will suggest simply generating an infinite number of connection (by never removing them), or using a single connection. The reason these approaches won't work is because I am writing a server. Since it is likely to be running for an extended period of time (assuming I've done my job), generating an infinite number of connections will result in a problem somewhere down the line. At the same time, since it is a server, it makes sense to be constantly spinning up new threads (one for each network connection), so using a single database connection from all of these threads isn't going to work.

momeni
4th July 2010, 07:08
Ohhh... You do not need it at all :)
Just let the QSqlDatabase non-pointer member object to be removed by finishing your class destructor.
Then Qt will close the connection automatically for you :D
See this point at Qt documentation:

QSqlDatabase::~QSqlDatabase ()

Destroys the object and frees any allocated resources.

If this is the last QSqlDatabase object that uses a certain database connection, the is automatically closed.