Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Problem with SQLite Database and threads "Database is locked"
Forum Update on Monday, May 27th 2025

Problem with SQLite Database and threads "Database is locked"

Scheduled Pinned Locked Moved General and Desktop
threaddatabase
14 Posts 4 Posters 5.8k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • SGaistS SGaist

    Hi,

    How are you passing the main DB connection to your threads ?

    D Offline
    D Offline
    davidesalvetti
    wrote on last edited by
    #5

    @SGaist I have a global file that contains the declaration of the main DB, that is included in all the three threads.

    1 Reply Last reply
    0
    • Kent-DorfmanK Kent-Dorfman

      I believe sqlite concurrency only works for pure read operations. I think your clone operations are considered writes, even though they are to different databases.

      D Offline
      D Offline
      davidesalvetti
      wrote on last edited by
      #6

      @Kent-Dorfman so what should I do to avoid this problem?

      1 Reply Last reply
      0
      • KroMignonK KroMignon

        @davidesalvetti Hi, I don' remember where I found this, but since Qt 5.11, sharing the same connection between threads is not allowed.
        You have to create a QSqlDatabase for each thread. The easiest is to add the thread id to the connection name to avoid name collision.
        Something like this:

        QSqlDatabase MyClass::getDBConnection()
        {
            // Starting with Qt 5.11, sharing the same connection between threads is not allowed.
            // Use a dedicated connection for each thread requiring access to the database,
            // using the thread address as connection name.
        
            QSqlDatabase cnx;
        
            QString dbName = QStringLiteral("myConnection_%1").arg(qintptr(QThread::currentThreadId()), 0, 16);
            if(QSqlDatabase::contains(dbName))
            {
                cnx = QSqlDatabase::database(dbName);
            }
            else
            {
                cnx = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName);
                cnx.setDatabaseName(m_dbPath);
                cnx.setConnectOptions("QSQLITE_BUSY_TIMEOUT=1000");
                if (!cnx.isValid() || !cnx.open())
                {
                    qDebug() << "DB connection creation error!";
                }
            }
            return cnx;
        }
        
        
        D Offline
        D Offline
        davidesalvetti
        wrote on last edited by
        #7

        @KroMignon I didn't specified it but I'm using it 5.9.1 with MinGW 32 bit compiler, do you think it can be something that happens also in previous versions?

        KroMignonK 1 Reply Last reply
        0
        • D davidesalvetti

          @KroMignon I didn't specified it but I'm using it 5.9.1 with MinGW 32 bit compiler, do you think it can be something that happens also in previous versions?

          KroMignonK Offline
          KroMignonK Offline
          KroMignon
          wrote on last edited by KroMignon
          #8

          @davidesalvetti I don't remember exactly what the problem is, but when QSqlDatabase() is not created in the same thread in which is it used, then something goes wrong internally.
          To avoid this kind of issues, starting with Qt 5.11, Qt does not allow to used QSqlDatabase() is another thread as in own.

          So yes, it is a bad practice to use same QSqlDatabase() in multiple threads.

          Addendum: when cloning database with QSqlDatabase::cloneDatabase(), don't forget to call open(), as you can see in documentation:

          Note: The new connection has not been opened. Before using the new connection, you must call open().

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          D 1 Reply Last reply
          2
          • KroMignonK KroMignon

            @davidesalvetti I don't remember exactly what the problem is, but when QSqlDatabase() is not created in the same thread in which is it used, then something goes wrong internally.
            To avoid this kind of issues, starting with Qt 5.11, Qt does not allow to used QSqlDatabase() is another thread as in own.

            So yes, it is a bad practice to use same QSqlDatabase() in multiple threads.

            Addendum: when cloning database with QSqlDatabase::cloneDatabase(), don't forget to call open(), as you can see in documentation:

            Note: The new connection has not been opened. Before using the new connection, you must call open().

            D Offline
            D Offline
            davidesalvetti
            wrote on last edited by
            #9

            @KroMignon thanks for your answer. Yes, I'm opening the connection and debugging I can see that it opens the it.

            What I didn't understand quite well is:
            I can't use the same QSqlDatabase() in different threads or I can't connect to the same database in different threads? I'm cloning the main QSqlDatabase so I have different instances of QSqlDatabase, each one on it's own thread, is this a problem? Or using different instances it's correct?

            KroMignonK 1 Reply Last reply
            0
            • D davidesalvetti

              @KroMignon thanks for your answer. Yes, I'm opening the connection and debugging I can see that it opens the it.

              What I didn't understand quite well is:
              I can't use the same QSqlDatabase() in different threads or I can't connect to the same database in different threads? I'm cloning the main QSqlDatabase so I have different instances of QSqlDatabase, each one on it's own thread, is this a problem? Or using different instances it's correct?

              KroMignonK Offline
              KroMignonK Offline
              KroMignon
              wrote on last edited by
              #10

              @davidesalvetti said in Problem with SQLite Database and threads "Database is locked":

              I can't use the same QSqlDatabase() in different threads or I can't connect to the same database in different threads?

              You can/should only use QSqlDatabase() in the thread in which it has been created.
              All QSqlDatabase() created in main thread, must only be used in main thread. QSqlDatabase() must be create in the thread in which you want to use it.
              This is why I've create a little function which create a new QSqlDatabase() when I need to dialog with database. So I am always sure the QSqlDatabase() I use is the right one.
              You should never store locally in your class a QSqlDatabase() instance, only create one when you need it, and destroy it after. This is the recommended usage for QSqlDatabase().

              Extract for QSqlDatabase documentation:

              Warning: It is highly recommended that you do not keep a copy of the QSqlDatabase around as a member of a class, as this will prevent the instance from being correctly cleaned up on shutdown. If you need to access an existing QSqlDatabase, it should be accessed with database(). If you chose to have a QSqlDatabase member variable, this needs to be deleted before the QCoreApplication instance is deleted, otherwise it may lead to undefined behavior.

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              D 1 Reply Last reply
              3
              • KroMignonK KroMignon

                @davidesalvetti said in Problem with SQLite Database and threads "Database is locked":

                I can't use the same QSqlDatabase() in different threads or I can't connect to the same database in different threads?

                You can/should only use QSqlDatabase() in the thread in which it has been created.
                All QSqlDatabase() created in main thread, must only be used in main thread. QSqlDatabase() must be create in the thread in which you want to use it.
                This is why I've create a little function which create a new QSqlDatabase() when I need to dialog with database. So I am always sure the QSqlDatabase() I use is the right one.
                You should never store locally in your class a QSqlDatabase() instance, only create one when you need it, and destroy it after. This is the recommended usage for QSqlDatabase().

                Extract for QSqlDatabase documentation:

                Warning: It is highly recommended that you do not keep a copy of the QSqlDatabase around as a member of a class, as this will prevent the instance from being correctly cleaned up on shutdown. If you need to access an existing QSqlDatabase, it should be accessed with database(). If you chose to have a QSqlDatabase member variable, this needs to be deleted before the QCoreApplication instance is deleted, otherwise it may lead to undefined behavior.

                D Offline
                D Offline
                davidesalvetti
                wrote on last edited by
                #11

                @KroMignon The problem is that I have created three different QsqlDatabase() in three different thread, and in every thread I use the QSqlDatabase() created in that thread. In this way it should work but it keeps giving me the problem. But I'll do more tests.

                Anyway I found a workaround for my personal application, but maybe other people may be interested in a solution.

                1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #12

                  What workaround is that ?

                  Can you show how you are creating your database object in these threads ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  D 1 Reply Last reply
                  0
                  • SGaistS SGaist

                    What workaround is that ?

                    Can you show how you are creating your database object in these threads ?

                    D Offline
                    D Offline
                    davidesalvetti
                    wrote on last edited by
                    #13

                    @SGaist The workaround is good only for a few people. Since I always worked with two different threads (the main thread and another thread) that have access to the database, I'm just telling the second thread to do the things that the third thread should do with the database, but obviously is just a solution for my case.

                    this is the way I'm createing the database connection:

                    void T_Analysis::connectDB()
                    {
                        db_2 = QSqlDatabase::cloneDatabase(db,"second");    
                    
                        if(!db_2.open())
                        {
                            qDebug() << "error";
                        }
                        else
                        {
                            qDebug() << "okdb_2";
                        }
                    }
                    
                    void T_Usb::connectDB()
                    {
                        db_3 = QSqlDatabase::cloneDatabase(db,"third");    
                    
                        if(!db_3.open())
                        {
                            qDebug() << "error";
                        }
                        else
                        {
                            qDebug() << "okdb_3";
                        }
                    }
                    

                    Main thread:

                    void MainWindow::connect()
                    {
                         db = QSqlDatabase::addDatabase("QSQLITE");
                        db.setDatabaseName("Prova.db");
                    
                        if (!db.open())
                        {
                                 //.... some code
                        }
                    
                    KroMignonK 1 Reply Last reply
                    0
                    • D davidesalvetti

                      @SGaist The workaround is good only for a few people. Since I always worked with two different threads (the main thread and another thread) that have access to the database, I'm just telling the second thread to do the things that the third thread should do with the database, but obviously is just a solution for my case.

                      this is the way I'm createing the database connection:

                      void T_Analysis::connectDB()
                      {
                          db_2 = QSqlDatabase::cloneDatabase(db,"second");    
                      
                          if(!db_2.open())
                          {
                              qDebug() << "error";
                          }
                          else
                          {
                              qDebug() << "okdb_2";
                          }
                      }
                      
                      void T_Usb::connectDB()
                      {
                          db_3 = QSqlDatabase::cloneDatabase(db,"third");    
                      
                          if(!db_3.open())
                          {
                              qDebug() << "error";
                          }
                          else
                          {
                              qDebug() << "okdb_3";
                          }
                      }
                      

                      Main thread:

                      void MainWindow::connect()
                      {
                           db = QSqlDatabase::addDatabase("QSQLITE");
                          db.setDatabaseName("Prova.db");
                      
                          if (!db.open())
                          {
                                   //.... some code
                          }
                      
                      KroMignonK Offline
                      KroMignonK Offline
                      KroMignon
                      wrote on last edited by KroMignon
                      #14

                      @davidesalvetti Hmm, I am not very confident in your solution. I would create a helper class to create/use right connection according to current thread.
                      Something like this (it is just a skeleton, not sure it is working as it is):

                      #include <QSqlDatabase>
                      #include <QThread>
                      
                      class MyBDConnection
                      {
                          QString m_dbPath;
                          QString m_dbName;
                          Q_DISABLE_COPY(MyBDConnection)
                      public:
                          explicit MyBDConnection(const QString &sqlitePath, const QString &cnxName): 
                                                                          m_dbPath(sqlitePath), m_dbName(cnxName) 
                          {}
                      
                          QSqlDatabase getDBConnection()
                          {
                              // Starting with Qt 5.11, sharing the same connection between threads is not allowed.
                              // Use a dedicated connection for each thread requiring access to the database,
                              // using the thread address as connection name.
                      
                              QSqlDatabase cnx;
                      
                              QString dbName = QStringLiteral("%1_%2").arg(m_dbName).arg(qintptr(QThread::currentThreadId()), 0, 16);
                              if(QSqlDatabase::contains(dbName))
                              {
                                  cnx = QSqlDatabase::database(dbName);
                              }
                              else
                              {
                                  cnx = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName);
                                  cnx.setDatabaseName(m_dbPath);
                                  if (!cnx.isValid() || !cnx.open())
                                  {
                                      qDebug() << "DB connection creation error!";
                                  }
                              }
                              return cnx;
                          }
                      }
                      

                      And the only create on instance of this class and pass the pointer to each class which need connection to DB.

                      It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved