QMYSQLResult :: cleanup:无法释放语句句柄

时间:2015-07-27 15:31:43

标签: qt

我正在尝试使用线程从MySQL数据库中获取数据,但是在调用:

之后
QThread* thread = new QThread;
Beacon *beacon = new Beacon(m_db, begin, end);
beacon->moveToThread(thread);
connect(beacon, &Beacon::values, this, &Tm::insertRow);
connect(beacon, &Beacon::finished, thread, &QThread::quit);
connect(beacon, &Beacon::finished, beacon, &Beacon::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
connect(thread, &QThread::started, beacon, &Beacon::executeQuerySmooth);
connect(beacon, &Beacon::finished, this, &Tm::finished);
thread->start();

我明白了:

QMYSQLResult::cleanup: unable to free statement handle

下次尝试使用连接时我得到了:

QSqlError("2006", "QMYSQL: Unable to execute query", "MySQL server has gone away")

可能会发生什么?

1 个答案:

答案 0 :(得分:2)

您只能使用创建它的线程(reference)的连接,或者通常仅使用一个线程的连接。

您可以采取两种方法:

  1. 在专用线程中维护数据库连接,并从那里使用它。无论如何,使用短线程是一种过早的悲观,因此开始时这是一个糟糕的方法。

  2. 从线程池中移动工作线程之间的数据库连接。使用QtConcurrent::run在线程池的线程上运行仿函数。

  3. 注意:Beacon::Beacon(...)构造函数无法使用数据库,它只能存储一个引用/指针!

    有关postCall的更多信息,请参阅this answer

    template <typename T>
    void postCall(QThread * thread, T && functor) {
       QObject source;
       QObject::connect(&source, &QObject::destroyed,
                        QEventDispatcher::instance(thread), std::forward(functor));
    }
    

    来自线程池的工作人员

    class Tm : public QObject {
      Q_OBJECT
      QMutex m_dbMutex;
      QSqlDatabase m_db;
      Q_SIGNAL void openFailed();
      Q_SIGNAL void openSucceeded();
    public:
      void openConnection() {
        QMutexLocker lock(&m_dbMutex);
        m_db.addDatabase("QSQLITE");
        ... // set database's properties
        m_db.moveToThread(0); // we don't know what thread it will be used in
        lock.unlock();
        QtConcurrent::run([this]{
          QMutexLocker lock(&m_dbMutex);
          m_db.moveToThread(QThread::currentThread());
          bool rc = m_db.open();
          if (rc) {
            m_db.moveToThread(0);
            emit openSucceeded();
          } else {
            m_db.moveToThread(this->thread());
            emit openFailed();
          }
        });
      }
      void beaconate() {
        ...
        QSharedPointer<Beacon> beacon(new Beacon(&m_db, begin, end));
        connect(beacon, &Beacon::values, this, &Tm::insertRow);
        connect(beacon, &Beacon::finished, this, &Tm::finished);
        beacon->setMoveToThread(0);
        QtConcurrent::run([beacon]{
          beacon->moveToThread(QThread::currentThread());
          QMutexLocker lock(&m_dbMutex);
          m_db.moveToThread(QThread::currentThread());
          QEventLoop loop; // only if Beacon needs one
          connect(beacon, &Beacon::finished, &loop, &QEventLoop::quit);
          beacon->executeQuerySmooth();
          loop.exec();
          m_db.moveToThread(0);
        });
      }
      ~Tm() {
        QMutexLocker lock(&m_dbMutex);
        m_db.moveToThread(thread());
      }
      ...
    };
    

    专用线程

    class Thread : public QThread
    { using QThread::run; public: ~Thread() { quit(); wait(); } };
    
    class Tm : public QObject {
      Q_OBJECT
      QSqlDatabase m_db;
      Thread m_dbThread; // must be declared after m_db, so that it's destructed prior to m_db
      Q_SIGNAL void openFailed();
      Q_SIGNAL void openSucceeded();
    public:
      Tm(QObject * parent = 0) : QObject(parent) {
        m_dbThread.start();
      }
      void openConnection() {
        m_db.addDatabase("QSQLITE");
        ... // set database's properties
        m_db.moveToThread(&m_dbThread);
        postCall(&m_dbThread, [this]{
          if (! m_db.open()) {
            m_db.moveToThread(this->thread());
            emit openFailed();
          } else
            emit openSucceeded();
        });
      }
      void beaconate() {
        ...
        auto beacon = new Beacon(&m_db, begin, end);
        beacon.moveToThread(&m_dbThread);
        connect(beacon, &Beacon::values, this, &Tm::insertRow);
        connect(beacon, &Beacon::finished, beacon, &Beacon::deleteLater);
        connect(beacon, &Beacon::finished, this, &Tm::finished);
        postCall(&m_dbThread, [beacon]{ beacon->executeQuerySmooth(); });
      }
      ~Tm() {
        // Destructing objects living in other threads is undefined behavior
        postCall(&m_dbThread, [this]{ 
          if (m_db.thread() == QThread::currentThread())         
            m_db.moveToThread(thread());
        });
      }
      ...
    };