Qt Creator中自定义Database类致SQLite驱动加载失败求助
Qt SQLite 驱动加载失败问题排查与解决
问题场景
使用Qt Creator 8.0.2开发程序,直接在MainWindow构造函数中打开SQLite数据库连接正常,但调用自定义Database类的方法时,连接失败并报错:Error open QSqlError("", "Driver not loaded", "Driver not loaded"),已排查12小时,寻求实例、指针相关的问题分析与解决方法。
可正常运行的mainwindow.cpp
#include "HeaderLibary.h" #include "ui_mainwindow.h" #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); this->setMaximumHeight(MAX_WINDOW_HEIGHT); this->setMinimumHeight(MIN_WINDOW_HEIGHT); this->setMaximumWidth(MAX_WINDOW_WIDTH); this->setMinimumWidth(MIN_WINDOW_WIDTH); QFont font; font.setPixelSize(FONT_SIZE); font.setBold(true); font.setFamily(FONT_FAMILY); QString buffer; QGridLayout *windowLayout = new QGridLayout; matrix *inputMatrix = new matrix("input",MAXLENGTH,false,QLINEEDIT_HEIGHT,QLINEEDIT_WIDTH,font,5,5,true,1); inputMatrix->set_matrix(); this->inputWidgets = inputMatrix->getMatrixWidgets(); buffer = "Hello User, welcome to AES - Advanced Encryption Standard!"; QLabel *title = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT); font.setPointSize(FONT_SIZE_TEXT); buffer = "With AES you can encrypt messages of up to 16 characters or 16 Bytes." "\n\nPlease enter your message in this matrix. One character per field in numbered order."; QLabel *text = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT); QPushButton *startBtn = inputMatrix->setButton("Start",BTN_WIDTH,BTN_HEIGHT); connect(startBtn,SIGNAL(clicked()),this,SLOT(start_clicked())); windowLayout->addWidget(title,0,0,1,2,Qt::AlignCenter); windowLayout->addWidget(text,1,0,1,2,Qt::AlignCenter); windowLayout->addLayout(inputMatrix->getLayout(),2,0,1,2,Qt::AlignCenter); windowLayout->addWidget(startBtn,3,1,1,1,Qt::AlignRight); QWidget *widget = new QWidget(); widget->setLayout(windowLayout); setCentralWidget(widget); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("AES_DB.db"); if(!db.open()) qDebug()<< db.lastError(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::start_clicked() { QSqlDatabase db; QSqlQuery qry; QString tableName = "orginalMsgLetters"; QString buffer= QString("DROP TABLE %1;").arg(tableName); if(!qry.exec(buffer)) qDebug()<< qry.lastError(); buffer = QString("CREATE TABLE IF NOT EXISTS %1 (id INTEGER NOT NULL PRIMARY KEY, itemValue VARCHAR(20));").arg(tableName); if(!qry.exec(buffer)) qDebug()<< qry.lastError(); bool check = false; int index = 0; while(!check){ if(inputWidgets->at(index)->text() == ""){ QMessageBox::information(this,tr("Error"), tr("Please fill out each box to continue")); return; } else if(inputWidgets->at(index)->text() == "ü" || inputWidgets->at(index)->text() == "ä" || inputWidgets->at(index)->text() == "ö" || inputWidgets->at(index)->text() == "ß"){ QMessageBox::information(this,tr("Error"), tr("Please don't use Ü/ü, Ä/ä, Ö/ö or ß ")); return; } else { if(index+1 == MAXLENGTH) check = true; else index++; } } for (int i = 0; i < MAXLENGTH; ++i) { buffer=QString("INSERT INTO %1 (id,itemValue)VALUES (%2,%3);").arg(tableName).arg(i).arg(this->inputWidgets->at(i)->text()); if(!qry.exec(buffer)) qDebug()<<qry.lastError(); buffer=QString("SELECT * FROM %1 WHERE id=%2").arg(tableName).arg(i); if(!qry.exec(buffer)) qDebug()<<qry.lastError(); while(qry.next()) qDebug()<< qry.value(1).toString(); } db.close(); }
mainwindow.h
#pragma once #include "HeaderLibary.h" #include "Config_File.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT private: QList<QLineEdit*>* inputWidgets; //Database *db = new Database(); QSqlDatabase *db = new QSqlDatabase; QSqlQuery *qry = new QSqlQuery; public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void start_clicked(); private: Ui::MainWindow *ui; };
导致错误的Database.cpp
#include "database.h" Database::Database(){ } Database::~Database(){ } void Database::deleteTable(QString tableName){ QSqlQuery qry; QString buffer = QString("DROP TABLE %1;").arg(tableName); qry.prepare(buffer); qry.exec(); } void Database::connect(){ QSqlDatabase db; db.addDatabase("QSQLITE"); db.setDatabaseName("AES_DB.db"); if(!db.open()) qDebug()<< "Error open "<< db.lastError(); } void Database::addValueToTable(QString tableName,int id, QString value){ QSqlQuery qry; QString buffer = QString("INSERT INTO %1 (id,itemValue)VALUES (%2,%3);").arg(tableName).arg(id).arg(value); qry.prepare(buffer); if(!qry.exec()){ qDebug()<< qry.lastError(); qDebug()<< "\n insert Error \n"; } } void Database::createTable(QString tableName){ QSqlQuery qry; QString buffer = QString("CREATE TABLE IF NOT EXISTS %1 (id INTEGER NOT NULL PRIMARY KEY, itemValue VARCHAR(20));").arg(tableName); if(!qry.exec(buffer)){ qDebug()<< qry.lastError(); qDebug()<< "\n create Error \n"; } } void Database::close(){ QSqlDatabase db; db.close(); } QString Database::getValueFromTable(QString tableName,int id){ QSqlQuery qry; QString string = QString("SELECT * FROM %1 WHERE id=%2").arg(tableName).arg(id); qry.prepare(string); if(!qry.exec(string)){ qDebug()<< qry.lastError(); qDebug()<< "\n get Error \n"; } while(qry.next()) return qry.value(1).toString(); }
database.h
#pragma once #include "Config_File.h" #include "HeaderLibary.h" class Database { private: public: Database(); ~Database(); void connect(); void addValueToTable(QString tableName,int id, QString value); void deleteTable (QString tableName); void createTable(QString tableName); QString getValueFromTable(QString tableName,int id); void close(); };
核心问题分析
- QSqlDatabase实例生命周期错误
Database类的connect()方法中,QSqlDatabase db是局部变量,调用addDatabase后,局部变量销毁时会自动移除数据库连接,导致后续操作无有效连接。 - QSqlQuery未绑定有效连接
Database类中所有QSqlQuery都是局部创建,未指定关联的数据库连接,默认使用无连接实例,引发驱动加载失败。 - MainWindow中错误创建QSqlDatabase指针
QSqlDatabase *db = new QSqlDatabase;是错误用法,QSqlDatabase必须通过addDatabase静态方法创建,不能直接new。
修复方案
1. 修改Database类,保存数据库连接为成员变量
database.h
#pragma once #include "Config_File.h" #include "HeaderLibary.h" class Database { private: QSqlDatabase m_db; // 成员变量保存数据库连接 public: Database(); ~Database(); bool connect(); // 返回连接状态,方便调用者判断 void addValueToTable(QString tableName,int id, QString value); void deleteTable (QString tableName); void createTable(QString tableName); QString getValueFromTable(QString tableName,int id); void close(); };
Database.cpp
#include "database.h" Database::Database(){ m_db = QSqlDatabase::addDatabase("QSQLITE"); } Database::~Database(){ if(m_db.isOpen()){ m_db.close(); } } bool Database::connect(){ m_db.setDatabaseName("AES_DB.db"); if(!m_db.open()){ qDebug()<< "Error open "<< m_db.lastError(); return false; } return true; } void Database::deleteTable(QString tableName){ QSqlQuery qry(m_db); // 绑定到成员变量的数据库连接 QString buffer = QString("DROP TABLE %1;").arg(tableName); if(!qry.exec(buffer)){ qDebug()<< qry.lastError(); } } void Database::addValueToTable(QString tableName,int id, QString value){ QSqlQuery qry(m_db); // 使用占位符避免SQL注入,同时解决字符串引号问题 QString buffer = QString("INSERT INTO %1 (id,itemValue)VALUES (:id, :value);").arg(tableName); qry.prepare(buffer); qry.bindValue(":id", id); qry.bindValue(":value", value); if(!qry.exec()){ qDebug()<< qry.lastError(); qDebug()<< "\n insert Error \n"; } } void Database::createTable(QString tableName){ QSqlQuery qry(m_db); QString buffer = QString("CREATE TABLE IF NOT EXISTS %1 (id INTEGER NOT NULL PRIMARY KEY, itemValue VARCHAR(20));").arg(tableName); if(!qry.exec(buffer)){ qDebug()<< qry.lastError(); qDebug()<< "\n create Error \n"; } } void Database::close(){ if(m_db.isOpen()){ m_db.close(); } } QString Database::getValueFromTable(QString tableName,int id){ QSqlQuery qry(m_db); QString string = QString("SELECT * FROM %1 WHERE id=:id").arg(tableName); qry.prepare(string); qry.bindValue(":id", id); if(!qry.exec()){ qDebug()<< qry.lastError(); qDebug()<< "\n get Error \n"; return ""; } if(qry.next()){ return qry.value(1).toString(); } return ""; }
2. 修复MainWindow类的数据库指针
mainwindow.h
#pragma once #include "HeaderLibary.h" #include "Config_File.h" #include "database.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT private: QList<QLineEdit*>* inputWidgets; Database* m_db; // 使用自定义Database类 public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: void start_clicked(); private: Ui::MainWindow *ui; };
mainwindow.cpp
#include "HeaderLibary.h" #include "ui_mainwindow.h" #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_db(new Database()) { ui->setupUi(this); this->setMaximumHeight(MAX_WINDOW_HEIGHT); this->setMinimumHeight(MIN_WINDOW_HEIGHT); this->setMaximumWidth(MAX_WINDOW_WIDTH); this->setMinimumWidth(MIN_WINDOW_WIDTH); QFont font; font.setPixelSize(FONT_SIZE); font.setBold(true); font.setFamily(FONT_FAMILY); QString buffer; QGridLayout *windowLayout = new QGridLayout; matrix *inputMatrix = new matrix("input",MAXLENGTH,false,QLINEEDIT_HEIGHT,QLINEEDIT_WIDTH,font,5,5,true,1); inputMatrix->set_matrix(); this->inputWidgets = inputMatrix->getMatrixWidgets(); buffer = "Hello User, welcome to AES - Advanced Encryption Standard!"; QLabel *title = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT); font.setPointSize(FONT_SIZE_TEXT); buffer = "With AES you can encrypt messages of up to 16 characters or 16 Bytes." "\n\nPlease enter your message in this matrix. One character per field in numbered order."; QLabel *text = inputMatrix->setLabel(buffer,MAX_WINDOW_WIDTH,LABEL_HIGHT); QPushButton *startBtn = inputMatrix->setButton("Start",BTN_WIDTH,BTN_HEIGHT); connect(startBtn,SIGNAL(clicked()),this,SLOT(start_clicked())); windowLayout->addWidget(title,0,0,1,2,Qt::AlignCenter); windowLayout->addWidget(text,1,0,1,2,Qt::AlignCenter); windowLayout->addLayout(inputMatrix->getLayout(),2,0,1,2,Qt::AlignCenter); windowLayout->addWidget(startBtn,3,1,1,1,Qt::AlignRight); QWidget *widget = new QWidget(); widget->setLayout(windowLayout); setCentralWidget(widget); if(!m_db->connect()){ qDebug() << "数据库连接失败"; } } MainWindow::~MainWindow() { delete m_db; delete ui; } void MainWindow::start_clicked() { QString tableName = "orginalMsgLetters"; m_db->deleteTable(tableName); m_db->createTable(tableName); bool check = false; int index = 0; while(!check){ if(inputWidgets->at(index)->text() == ""){ QMessageBox::information(this,tr("Error"), tr("Please fill out each box to continue")); return; } else if(inputWidgets->at(index)->text() == "ü" || inputWidgets->at(index)->text() == "ä" || inputWidgets->at(index)->text() == "ö" || inputWidgets->at(index)->text() == "ß"){ QMessageBox::information(this,tr("Error"), tr("Please don't use Ü/ü, Ä/ä, Ö/ö or ß ")); return; } else { if(index+1 == MAXLENGTH) check = true; else index++; } } for (int i = 0; i < MAXLENGTH; ++i) { m_db->addValueToTable(tableName, i, inputWidgets->at(i)->text()); QString value = m_db->getValueFromTable(tableName, i); qDebug() << value; } }
额外注意事项
- SQL注入风险:原代码直接拼接用户输入到SQL语句中,修复后使用
bindValue占位符避免该问题。 - 驱动验证:若修复后仍报错,可在程序启动时打印可用驱动:
确保输出包含qDebug() << QSqlDatabase::drivers();QSQLITE,若缺失需检查Qt安装包是否包含SQLite驱动,或手动编译驱动。
内容的提问来源于stack exchange,提问作者Cryptos90
相关产品推荐
相关产品推荐

