2011-03-19 89 views
3

我正在構建一個基於Qt的應用程序來監視和捕獲串口數據流。數據實時繪製,通過TCP發送出去,並存儲到SQLite數據庫中。不幸的是,我發現SQLite插入會導致GUI無響應,因爲我正在主循環的上下文中執行串行數據處理,繪圖,TCP傳輸和數據庫插入。我研究了將數據庫插入分離到另一個線程,並提出以下代碼。Qt SQL線程數據庫查詢

#include <QObject> 
#include <QDebug> 
#include <QStringList> 
#include <QSqlDatabase> 
#include <QSqlQuery> 
#include <QSqlError> 
#include <QVariant> 
#include <QObject> 
#include <QList> 
#include <QThread> 
#include <QMutex> 
#include <QWaitCondition> 
#include <QSqlDatabase> 
#include <QSqlRecord> 
#include <QString> 
#include "mMessage.h" 
// The class that does all the work with the database. This class will 
// be instantiated in the thread object's run() method. 
class Worker : public QObject 
{ 
    Q_OBJECT 
    public: 
    Worker(QObject* parent = 0); 
    ~Worker(); 
    bool insertADC(mMessage* insertMessage); 
    public slots: 
    void slotExecute(mMessage* insertMessage); 
    signals: 
    void queryResult(bool); 
    private: 
    QSqlDatabase m_database; 
    bool m_databaseOpen; 
    void prepareQueries(); 
    QSqlQuery *m_accelerometerQuery; 
    QSqlQuery *m_adcQuery; 
    QSqlQuery *m_metricsQuery; 
    QSqlQuery *m_rssiQuery; 
}; 

class mDatabaseThread : public QThread 
{ 
    Q_OBJECT 
    public: 
    mDatabaseThread(QObject *parent = 0); 
    ~mDatabaseThread(); 
    void executeInsertion(mMessage* insertMessage); 
    signals: 
    void progress(const QString& msg); 
void ready(bool); 
    protected: 
    void run(); 
    signals: 
    void executefwd(mMessage* insertMessage); 
    private: 
    Worker* m_worker; 
}; 

CPP FILE

#include "mDatabaseThread.h" 
    // 

    Worker::Worker(QObject* parent) 
     : QObject(parent) 
    { 
     // thread-specific connection, see db.h 
     m_database = QSqlDatabase::addDatabase("QSQLITE", 
               "WorkerDatabase"); // named connection 
     m_database.setDatabaseName("trainingX.db3"); 
     if (!m_database.open()) 
     { 
      qWarning() << "Unable to connect to database, giving up:" << m_database.lastError().text(); 
      m_databaseOpen = false; 
      return; 
     } 
    m_databaseOpen = true; 

    } 

    Worker::~Worker() 
    { 
     //close the database 
     // m_database.close(); 
     // m_database.removeDatabase("trainingX.db3"); 
    } 
    void Worker::prepareQueries() 
    { 
     if (m_databaseOpen) 
     { 
     m_accelerometerQuery->prepare("INSERT INTO accelerometer (key, timestamp, nickname, unitid," 
            "sectorid, acc_x, acc_y, acc_z) " 
            "VALUES (NULL, :timestamp, :nickname, :unitid, :sectorid," 
            ":acc_x, :acc_y, :acc_z)"); 

     m_adcQuery->prepare("INSERT INTO adc (key, timestamp, nickname, unitid, sectorid," 
         "adc0, adc1, adc2, adc3, adc4, adc5, adc6, adc7) " 
         "VALUES (NULL, :timestamp, :nickname, :unitid, :sectorid," 
         ":adc0, :adc1, :adc2, :adc3, :adc4, :adc5, :adc6, :adc7)"); 

     m_metricsQuery->prepare("INSERT INTO metrics (key, timestamp, nickname, unitid, sectorid, " 
          "acc_temp, unit_temp, unit_pressure, bpm_instant, bpm_average, base_pressure, base_temp) " 
          "VALUES (NULL, :timestamp, :nickname, :unitid, :sectorid," 
          ":acc_temp, :unit_temp, :unit_pressure, :bpm_instant, :bpm_average, :base_pressure, :base_temp)"); 

     m_rssiQuery->prepare("INSERT INTO rssi (key, timestamp, nickname, unitid, sectorid, " 
          "rssi_1, rssi_2, rssi_3, rssi_4, rssi_avg) " 
          "VALUES (NULL, :timestamp, :nickname, :unitid, :sectorid," 
          ":rssi_1, :rssi_2, :rssi_3, :rssi_4, :rssi_avg)"); 
     } 
    } 

    void Worker::slotExecute(mMessage* insertMessage) 
    { 
     m_accelerometerQuery = new QSqlQuery("WorkerDatabase"); 
     m_adcQuery = new QSqlQuery("WorkerDatabase"); 
     m_metricsQuery = new QSqlQuery("WorkerDatabase"); 
     m_rssiQuery = new QSqlQuery("WorkerDatabase"); 

     prepareQueries(); 

     insertADC(insertMessage); 
     //insertRSSI(insertMessage); 
     //insertAccelerometer(insertMessage); 
     //insertMetrics(insertMessage); 
     emit queryResult(true); 
    } 
bool Worker::insertADC(mMessage *insertMessage) 
{ 
    if (m_databaseOpen) 
    { 
      // m_adcQuery->bindValue(":key",0); 
      m_adcQuery->bindValue(":timestamp",insertMessage->m_timestamp); 
      m_adcQuery->bindValue(":nickname",insertMessage->m_nickname); 
      m_adcQuery->bindValue(":unitid",insertMessage->m_unitId.toInt()); 
      m_adcQuery->bindValue(":sectorid",insertMessage->m_sectorId.toInt()); 
      m_adcQuery->bindValue(":adc0",insertMessage->m_adc0.toInt()); 
      m_adcQuery->bindValue(":adc1",insertMessage->m_adc1.toInt()); 
      m_adcQuery->bindValue(":adc2",insertMessage->m_adc2.toInt()); 
      m_adcQuery->bindValue(":adc3",insertMessage->m_adc3.toInt()); 
      m_adcQuery->bindValue(":adc4",insertMessage->m_adc4.toInt()); 
      m_adcQuery->bindValue(":adc5",insertMessage->m_adc5.toInt()); 
      m_adcQuery->bindValue(":adc6",insertMessage->m_adc6.toInt()); 
      m_adcQuery->bindValue(":adc7",insertMessage->m_adc7.toInt()); 
      if (m_adcQuery->exec()) 
      { 
       return true; 
      } 
      else 
      { 
       qDebug() << "SQL ADC failed."; 
       qDebug() << m_adcQuery->lastError(); 
       return false; 
      } 
    } 
    else 
    { 
    //database isn't open 
    return false; 
    } 
} 
////database thread 

mDatabaseThread::mDatabaseThread(QObject *parent) 
    : QThread(parent) 
{ 
} 
mDatabaseThread::~mDatabaseThread() 
{ 
    delete m_worker; 
} 

void mDatabaseThread::executeInsertion(mMessage* insertMessage) 
{ 
    emit executefwd(insertMessage); // forwards to the worker 
} 

void mDatabaseThread::run() 
{ 
    emit ready(false); 
    // Create worker object within the context of the new thread 
    m_worker = new Worker(); 
    connect(this, SIGNAL(executefwd(mMessage*)), 
      m_worker, SLOT(slotExecute(mMessage*))); 
    connect(m_worker, SIGNAL(queryResult(bool)), this, SIGNAL(ready(bool))); 
    emit ready(true); 

    exec(); // our event loop 
} 

的mDatabaseThread類具有它發送數據庫工作一個工人對象。信號和插槽都正常工作並正確啓動。然而,實際的QSqlQuery失敗了,抱怨數據庫沒有打開 - 但是當我嘗試調試它時,我發現m_database實際上被設置爲正確的文件/參數。它基於這裏的解決方案http://www.linuxjournal.com/article/9602。 mMessage類是一個qObject,它也正確傳遞給m_worker對象。

從主類中,我在構造函數中調用m_databaseThread-> start(),然後調用executeInsertion(mMessage *)函數。我試圖改變m_database的初始化方式以及QSqlQueries,但似乎無論我做什麼,它都會抱怨QSqlQuery找不到數據庫連接。

回答

3

你很近。

因爲您給addDatabase()(「WorkerDatabase」)中的數據庫命名,所得到的連接不是應用程序默認值,並且不會返回QSqlDatabase()

正因爲如此,你需要通過數據庫對象QSqlQuery構造函數:

m_accelerometerQuery = new QSqlQuery(m_database); 

您的構造正在使用在這裏:

m_accelerometerQuery = new QSqlQuery("WorkerDatabase"); 

是:

QSqlQuery (const QString & query = QString(), QSqlDatabase db = QSqlDatabase()) 

當您傳入「WorkerDatabase」以將其存儲爲SQL查詢時,將爲數據庫存儲QSqlDatabase()返回的缺省(不存在)數據庫。

+0

現在就試試看,謝謝你的提示。我知道這是愚蠢的! – mhilmi 2011-03-19 22:44:55

+0

完美。好電話,你是個美男人! – mhilmi 2011-03-19 22:54:39