QSqlDatabase: невозможно использовать соединение из QThread

У меня есть два подключения к базе данных QSqlDatabase: «локальное» и «удаленное». У меня есть функция, которая использует оба соединения (получает данные из локальной базы данных и отправляет на удаленную базу данных). Когда я запускаю эту функцию из своего класса QThread, локальное соединение работает (я получил ожидаемые данные), но удаленное соединение не работает. Но если я запускаю эту функцию вне класса QThread (в main()), работают оба соединения.

Удаленное соединение завершается сбоем, когда я пытаюсь открыть соединение с сообщением об ошибке: «QSqlDatabasePrivate::database: невозможно открыть базу данных: QMYSQL: невозможно подключиться». Перед этим я проверил, действительно ли соединение (isValid()), и оно было в порядке. Я также проверяю, было ли уже открыто соединение, но это не так.

Я также нашел эту информацию, но поскольку «локальное» соединение работает из потока, это может быть не проблема:

Потоки и модуль SQL. Соединение можно использовать только из создавшего его потока. Перемещение соединений между потоками или создание запросов из другого потока не поддерживается. http://doc.qt.io/qt-5/threads-modules.html#threads-and-the-sql-module

Ошибка обнаружена в Qt 5.5.1, 32bit, Ubuntu 14.04. Также тестировался на Raspberry Pi, Qt 5.6, но в результате "ошибка сегментации".

Что не так?

main.c

main()
{
  DataHandler dh();
  DataHandlerThread dht(&dh); //pointer to dh to get access to dh functions from the thread

  //here I run dh.foo() or dht.run(), never both functions
  dh.foo();
  dht.run();
  ...
}

datahandler.cpp

DataHandler::DataHandler()
{
  m_dbLocal = QSqlDatabase::addDatabase("QMYSQL", "local");
  m_dbLocal.setHostName("localhost");
  ...

  m_dbRemote = QSqlDatabase::addDatabase("QMYSQL", "remote");
  m_dbRemote.setHostName(...);
  ...
}

DataHandler::foo()
{
  qDebug() << QSqlDatabase::connectionNames(); //always ("remote", "local")
  m_dbLocal.isValid(); //always true
  m_dbLocal.open(); //always true

  m_dbRemote.isValid(); //always true

  //true if foo() is called from main using dm.foo()
  //QSqlDatabasePrivate::database: unable to open database: " QMYSQL: Unable to connect" if called from main using dmt.run()
  m_dbRemote.open(); 
}

datahandlerthread.h

class DataHandlerThread : public QThread
{
    Q_OBJECT
public:
    explicit DataHandlerThread(DataHandler* dh);

private:
    void run() Q_DECL_OVERRIDE;

    DataHandler* m_dh;

};

datahandlerthread.cpp

DataHandlerThread::DataHandlerThread(DataHandler* dh)
{
    m_dh = dh;
}

void DataHandlerThread::run()
{
    m_dh->foo();
}

person Peder    schedule 02.06.2016    source источник
comment
Может быть, публикация кода поможет увидеть проблему?   -  person Silicomancer    schedule 02.06.2016
comment
Сообщение обновлено с кодом   -  person Peder    schedule 03.06.2016


Ответы (1)


Я нашел решение проблемы. Решение заключалось в создании новых экземпляров как локального, так и удаленного соединения в конструкторе DataHandlerThread:

datahandlerthread.cpp

DataHandlerThread::DataHandlerThread(DataHandler* dh)
{
  m_dh = dh;
  m_dbLocal = QSqlDatabase::addDatabase("QMYSQL", "local_thread");
  m_dbLocal.setHostName("localhost");
  ...

  m_dbRemote = QSqlDatabase::addDatabase("QMYSQL", "remote_thread");
  m_dbRemote.setHostName(...);
  ...
}

Насколько я понимаю, эти новые экземпляры также можно было создать с помощью QSqlDatabase::cloneDatabase() и передать эти новые экземпляры конструктору DataHandlerThread (не тестировалось).

Итак, похоже, что информация в ссылке «Потоки и модуль SQL» была несколько правильной. По какой-то причине "локальное" соединение все еще работало из потока.

person Peder    schedule 03.06.2016