5

I'm troubled by how the Sql module works with multithreaded application in Qt. http://doc.qt.io/qt-5/threads-modules.html#threads-and-the-sql-module clearly states that "A connection can only be used from within the thread that created it".

However this piece of code I wrote works :

#include <QCoreApplication>
#include <QSqlQuery>
#include <QtConcurrentRun>

void    req()
{
  QSqlQuery q("INSERT INTO users (username) VALUES (\"test\")");
}

void    db()
{
  QSqlDatabase _db;

  _db = QSqlDatabase::addDatabase("QMYSQL");
  _db.setDatabaseName("dbname");
  _db.setHostName("host");
  _db.setUserName("username");
  _db.setPassword("password");
  if (_db.open())
    std::cout << "Ok" << std::endl;
  else
    std::cout << "Error" << std::endl;
}

int     main(int ac, char **av)
{
  QCoreApplication app(ac, av);
  QtConcurrent::run(db);
  sleep(1);
  QtConcurrent::run(req);
  return app.exec();
}

My application design requires multiple threads to interact with a database. Thoses threads are spawned and managed by QtConcurrent::run().

So, since this piece of code works should I go for it or will I run into troubles doing that ?

Any help, documentation or explanation is welcome ! Thank you.

1 Answer 1

6

The above code is fine because QSqlQuery creates its own QSqlDatabase. It would be a problem if it referenced _db as created by db(). The down side is that it doesn't actually do anything.

QSqlDatabase is not a QObject but it has-a driver which is a QObject and therefore has thread affinity.

If creating loads of QSqlDatabases is prohibitive, create worker threads which maintains their own connection. Then dispatch queries to these threads rather than creating new threads and therefore new connections.

Sign up to request clarification or add additional context in comments.

4 Comments

What do you mean by "The down side is that it doesn't actually do anything." ? My query is executed, and the entry inserted. If I understand decently, QSqlQuery will create its own QSqlDatabase using the database configuration from the db created by QSqlDatabase::addDatabase() ? Does that imply a lot of overhead (because of objects' copies or something)?
Your QSqlQuery object knows nothing about the QSqlDatabase you also created because you're not using the "db connected" constructor QSqlQuery::QSqlQuery(QString&, QSqlDatabase) (i.e. you don't pass the pre-created db to the query). The way you instantiate the query means that a new, separate DB connection will be created/torn down each time req() is called. Which is thread-safe, but potentially expensive.
I did some more testing, and calling multiple QtConcurent::run(req) is causing the test program to segfault. edit: it seems that the query instanciation is not thread safe.
I'd guess that's because although many Qt method calls are reentrant, they're not always thread-safe, and the global database object is getting screwed-up. Create one QSqlDatabase per worker thread with its own connection, and create all queries in that thread from that database.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.