QT操作PostgreSQL數(shù)據(jù)庫并實現(xiàn)增刪改查功能
一、環(huán)境準備
1. 安裝 PostgreSQL
確保已安裝 PostgreSQL 并創(chuàng)建了測試數(shù)據(jù)庫。
2. 安裝 Qt 開發(fā)環(huán)境
確保已安裝 Qt 開發(fā)環(huán)境(Qt Creator 或命令行工具)。
3. 配置 Qt 連接 PostgreSQL
在項目文件(.pro)中添加:
QT += sql
二、連接 PostgreSQL 數(shù)據(jù)庫
1. 基本連接方式
#include <QCoreApplication> #include <QtSql/QSqlDatabase> #include <QtSql/QSqlError> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 創(chuàng)建數(shù)據(jù)庫連接 QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL"); // 設(shè)置連接參數(shù) db.setHostName("localhost"); // 主機名 db.setPort(5432); // 端口 db.setDatabaseName("testdb"); // 數(shù)據(jù)庫名 db.setUserName("postgres"); // 用戶名 db.setPassword("password"); // 密碼 // 打開連接 if (!db.open()) { qDebug() << "數(shù)據(jù)庫連接失敗:" << db.lastError().text(); return -1; } qDebug() << "成功連接到數(shù)據(jù)庫"; // 關(guān)閉連接 db.close(); return a.exec(); }
2. 使用連接池(推薦)
// 創(chuàng)建連接池 QSqlDatabase createConnectionPool(const QString &connectionName) { QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL", connectionName); db.setHostName("localhost"); db.setPort(5432); db.setDatabaseName("testdb"); db.setUserName("postgres"); db.setPassword("password"); if (!db.open()) { qCritical() << "創(chuàng)建連接池失敗:" << db.lastError().text(); return QSqlDatabase(); } return db; } // 獲取連接 QSqlDatabase getConnection(const QString &connectionName) { QSqlDatabase db = QSqlDatabase::database(connectionName); if (!db.isOpen()) { if (!db.open()) { qCritical() << "獲取連接失敗:" << db.lastError().text(); return QSqlDatabase(); } } return db; } // 釋放連接 void releaseConnection(const QString &connectionName) { QSqlDatabase::removeDatabase(connectionName); }
三、實現(xiàn)增刪改查操作
1. 創(chuàng)建測試表
首先在 PostgreSQL 中創(chuàng)建測試表:
CREATE TABLE employees ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, position VARCHAR(50), salary NUMERIC(10, 2), hire_date DATE );
2. 插入數(shù)據(jù)(Add)
bool insertEmployee(QSqlDatabase &db, const QString &name, const QString &position, double salary, const QDate &hireDate) { QSqlQuery query(db); // 使用預處理語句防止SQL注入 query.prepare("INSERT INTO employees (name, position, salary, hire_date) " "VALUES (:name, :position, :salary, :hire_date)"); query.bindValue(":name", name); query.bindValue(":position", position); query.bindValue(":salary", salary); query.bindValue(":hire_date", hireDate); if (!query.exec()) { qDebug() << "插入數(shù)據(jù)失敗:" << query.lastError().text(); return false; } return true; }
3. 查詢數(shù)據(jù)(Query)
3.1 查詢單條記錄
QSqlRecord getEmployeeById(QSqlDatabase &db, int id) { QSqlQuery query(db); query.prepare("SELECT * FROM employees WHERE id = :id"); query.bindValue(":id", id); if (!query.exec() || !query.next()) { qDebug() << "查詢員工失敗:" << query.lastError().text(); return QSqlRecord(); } return query.record(); }
3.2 查詢所有記錄
QList<QSqlRecord> getAllEmployees(QSqlDatabase &db) { QList<QSqlRecord> employees; QSqlQuery query(db); query.exec("SELECT * FROM employees ORDER BY id"); while (query.next()) { employees.append(query.record()); } return employees; }
3.3 使用模型查詢(Qt SQL 模型)
QSqlTableModel *createEmployeeModel(QObject *parent = nullptr) { QSqlTableModel *model = new QSqlTableModel(parent); model->setTable("employees"); model->select(); // 設(shè)置表頭 model->setHeaderData(1, Qt::Horizontal, tr("Name")); model->setHeaderData(2, Qt::Horizontal, tr("Position")); model->setHeaderData(3, Qt::Horizontal, tr("Salary")); model->setHeaderData(4, Qt::Horizontal, tr("Hire Date")); return model; }
4. 更新數(shù)據(jù)(Update)
bool updateEmployee(QSqlDatabase &db, int id, const QString &name, const QString &position, double salary, const QDate &hireDate) { QSqlQuery query(db); query.prepare("UPDATE employees SET name = :name, position = :position, " "salary = :salary, hire_date = :hire_date WHERE id = :id"); query.bindValue(":name", name); query.bindValue(":position", position); query.bindValue(":salary", salary); query.bindValue(":hire_date", hireDate); query.bindValue(":id", id); if (!query.exec()) { qDebug() << "更新員工失敗:" << query.lastError().text(); return false; } return true; }
5. 刪除數(shù)據(jù)(Delete)
bool deleteEmployee(QSqlDatabase &db, int id) { QSqlQuery query(db); query.prepare("DELETE FROM employees WHERE id = :id"); query.bindValue(":id", id); if (!query.exec()) { qDebug() << "刪除員工失敗:" << query.lastError().text(); return false; } return true; }
四、完整示例
1. 使用控制臺程序演示CRUD操作
#include <QCoreApplication> #include <QtSql/QSqlDatabase> #include <QtSql/QSqlQuery> #include <QtSql/QSqlError> #include <QtSql/QSqlRecord> #include <QDebug> #include <QDate> bool openDatabase(QSqlDatabase &db) { db = QSqlDatabase::addDatabase("QPSQL"); db.setHostName("localhost"); db.setPort(5432); db.setDatabaseName("testdb"); db.setUserName("postgres"); db.setPassword("password"); if (!db.open()) { qDebug() << "數(shù)據(jù)庫連接失敗:" << db.lastError().text(); return false; } return true; } void closeDatabase(QSqlDatabase &db) { db.close(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QSqlDatabase db; if (!openDatabase(db)) { return -1; } // 插入數(shù)據(jù) QSqlQuery query(db); query.prepare("INSERT INTO employees (name, position, salary, hire_date) " "VALUES (:name, :position, :salary, :hire_date)"); query.bindValue(":name", "張三"); query.bindValue(":position", "開發(fā)工程師"); query.bindValue(":salary", 15000.00); query.bindValue(":hire_date", QDate::currentDate()); if (!query.exec()) { qDebug() << "插入失敗:" << query.lastError().text(); } else { qDebug() << "插入成功,ID:" << query.lastInsertId().toInt(); } // 查詢數(shù)據(jù) QSqlQuery selectQuery(db); selectQuery.exec("SELECT * FROM employees ORDER BY id"); while (selectQuery.next()) { QSqlRecord record = selectQuery.record(); qDebug() << "ID:" << record.value("id").toInt() << "姓名:" << record.value("name").toString() << "職位:" << record.value("position").toString() << "薪資:" << record.value("salary").toDouble() << "入職日期:" << record.value("hire_date").toDate(); } // 更新數(shù)據(jù) query.prepare("UPDATE employees SET salary = :salary WHERE id = :id"); query.bindValue(":salary", 16000.00); query.bindValue(":id", 1); // 假設(shè)ID為1的員工 if (!query.exec()) { qDebug() << "更新失敗:" << query.lastError().text(); } else { qDebug() << "更新成功"; } // 刪除數(shù)據(jù) query.prepare("DELETE FROM employees WHERE id = :id"); query.bindValue(":id", 1); // 假設(shè)要刪除ID為1的員工 if (!query.exec()) { qDebug() << "刪除失敗:" << query.lastError().text(); } else { qDebug() << "刪除成功"; } closeDatabase(db); return a.exec(); }
2. 使用Qt Widgets實現(xiàn)GUI界面
// employeeform.h #ifndef EMPLOYEEFORM_H #define EMPLOYEEFORM_H #include <QWidget> #include <QSqlTableModel> #include <QDataWidgetMapper> QT_BEGIN_NAMESPACE namespace Ui { class EmployeeForm; } QT_END_NAMESPACE class EmployeeForm : public QWidget { Q_OBJECT public: EmployeeForm(QWidget *parent = nullptr); ~EmployeeForm(); private slots: void on_addButton_clicked(); void on_saveButton_clicked(); void on_deleteButton_clicked(); void on_refreshButton_clicked(); private: Ui::EmployeeForm *ui; QSqlTableModel *model; QDataWidgetMapper *mapper; }; #endif // EMPLOYEEFORM_H // employeeform.cpp #include "employeeform.h" #include "ui_employeeform.h" #include <QSqlDatabase> #include <QSqlError> #include <QMessageBox> EmployeeForm::EmployeeForm(QWidget *parent) : QWidget(parent) , ui(new Ui::EmployeeForm) { ui->setupUi(this); // 連接數(shù)據(jù)庫 QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL"); db.setHostName("localhost"); db.setPort(5432); db.setDatabaseName("testdb"); db.setUserName("postgres"); db.setPassword("password"); if (!db.open()) { QMessageBox::critical(this, "錯誤", "無法連接到數(shù)據(jù)庫: " + db.lastError().text()); return; } // 創(chuàng)建模型 model = new QSqlTableModel(this, db); model->setTable("employees"); model->select(); // 設(shè)置表頭 model->setHeaderData(1, Qt::Horizontal, tr("姓名")); model->setHeaderData(2, Qt::Horizontal, tr("職位")); model->setHeaderData(3, Qt::Horizontal, tr("薪資")); model->setHeaderData(4, Qt::Horizontal, tr("入職日期")); // 設(shè)置視圖 ui->tableView->setModel(model); ui->tableView->setEditTriggers(QAbstractItemView::DoubleClicked); // 設(shè)置數(shù)據(jù)映射器 mapper = new QDataWidgetMapper(this); mapper->setModel(model); mapper->addMapping(ui->nameEdit, 1); mapper->addMapping(ui->positionEdit, 2); mapper->addMapping(ui->salaryEdit, 3); mapper->addMapping(ui->hireDateEdit, 4); // 連接信號槽 connect(ui->tableView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, [this](const QModelIndex ¤t, const QModelIndex &) { mapper->setCurrentModelIndex(current); }); } EmployeeForm::~EmployeeForm() { delete ui; } void EmployeeForm::on_addButton_clicked() { int row = model->rowCount(); model->insertRow(row); ui->tableView->selectRow(row); mapper->setCurrentIndex(row); ui->nameEdit->setFocus(); } void EmployeeForm::on_saveButton_clicked() { if (!model->submitAll()) { QMessageBox::warning(this, "錯誤", "保存失敗: " + model->lastError().text()); } else { model->database().transaction(); if (model->submitAll()) { model->database().commit(); QMessageBox::information(this, "成功", "數(shù)據(jù)保存成功"); } else { model->database().rollback(); QMessageBox::warning(this, "錯誤", "保存失敗: " + model->lastError().text()); } } } void EmployeeForm::on_deleteButton_clicked() { QModelIndex index = ui->tableView->currentIndex(); if (index.isValid()) { int ret = QMessageBox::question(this, "確認", "確定要刪除這條記錄嗎?", QMessageBox::Yes | QMessageBox::No); if (ret == QMessageBox::Yes) { model->removeRow(index.row()); if (!model->submitAll()) { QMessageBox::warning(this, "錯誤", "刪除失敗: " + model->lastError().text()); model->revertAll(); } } } } void EmployeeForm::on_refreshButton_clicked() { model->select(); }
五、高級功能
1. 事務(wù)處理
bool performTransaction(QSqlDatabase &db) { db.transaction(); QSqlQuery query(db); bool success = true; // 執(zhí)行多個操作 if (!query.exec("INSERT INTO employees (...) VALUES (...)" )) { success = false; } if (!query.exec("UPDATE ...")) { success = false; } if (success) { db.commit(); } else { db.rollback(); } return success; }
2. 批量插入
bool batchInsertEmployees(QSqlDatabase &db, const QList<QVariantList> &employees) { QSqlDatabase::database().transaction(); QSqlQuery query(db); query.prepare("INSERT INTO employees (name, position, salary, hire_date) " "VALUES (?, ?, ?, ?)"); foreach (const QVariantList &employee, employees) { query.addBindValue(employee); if (!query.execBatch()) { QSqlDatabase::database().rollback(); return false; } } QSqlDatabase::database().commit(); return true; }
3. 使用存儲過程
bool callStoredProcedure(QSqlDatabase &db, int employeeId) { QSqlQuery query(db); query.prepare("CALL update_employee_salary(:id, :percentage)"); query.bindValue(":id", employeeId); query.bindValue(":percentage", 10); // 增加10% if (!query.exec()) { qDebug() << "調(diào)用存儲過程失敗:" << query.lastError().text(); return false; } return true; }
六、常見問題解決
1. 連接失敗
- 檢查PostgreSQL服務(wù)是否運行
- 驗證連接參數(shù)(主機名、端口、數(shù)據(jù)庫名、用戶名、密碼)
- 檢查防火墻設(shè)置
- 確保安裝了PostgreSQL客戶端庫
2. 中文亂碼
// 設(shè)置編碼 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
或者在連接字符串中指定編碼:
db.setConnectOptions("client_encoding=UTF8");
3. 性能優(yōu)化
- 使用預處理語句
- 批量操作代替單條操作
- 合理使用事務(wù)
- 為常用查詢創(chuàng)建索引
七、總結(jié)
Qt 提供了強大而靈活的數(shù)據(jù)庫訪問功能,通過 Qt SQL 模塊可以輕松實現(xiàn) PostgreSQL 數(shù)據(jù)庫的增刪改查操作。本文介紹了從基本連接到高級功能的實現(xiàn)方法,并提供了完整的代碼示例。在實際開發(fā)中,可以根據(jù)項目需求選擇合適的實現(xiàn)方式,結(jié)合事務(wù)處理、批量操作等技術(shù)提高應(yīng)用性能。
以上就是QT操作PostgreSQL數(shù)據(jù)庫并實現(xiàn)增刪改查功能的詳細內(nèi)容,更多關(guān)于QT操作PostgreSQL增刪改查的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于PostgreSQL/openGauss?的分布式數(shù)據(jù)庫解決方案
ShardingSphere-Proxy?作為透明數(shù)據(jù)庫代理,用戶無需關(guān)心?Proxy?如何協(xié)調(diào)背后的數(shù)據(jù)庫。今天通過本文給大家介紹基于PostgreSQL/openGauss?的分布式數(shù)據(jù)庫解決方案,感興趣的朋友跟隨小編一起看看吧2021-12-12sqoop 實現(xiàn)將postgresql表導入hive表
這篇文章主要介紹了sqoop 實現(xiàn)將postgresql表導入hive表,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12PostgreSQL中date_trunc函數(shù)的語法及一些示例
這篇文章主要給大家介紹了關(guān)于PostgreSQL中date_trunc函數(shù)的語法及一些示例的相關(guān)資料,DATE_TRUNC函數(shù)是PostgreSQL數(shù)據(jù)庫中用于截斷日期部分的函數(shù),文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-04-04Postgresql根據(jù)響應(yīng)數(shù)據(jù)反向?qū)崿F(xiàn)建表語句與insert語句的過程
根據(jù)已有數(shù)據(jù),可構(gòu)建名為products的表,包含id(自增主鍵)、title(非空字符串)、progress(非空整數(shù))三個字段,建表后,可通過insert語句插入數(shù)據(jù),這種反向操作有助于從現(xiàn)有數(shù)據(jù)結(jié)構(gòu)出發(fā),快速構(gòu)建數(shù)據(jù)庫表,并進行數(shù)據(jù)填充,感興趣的朋友跟隨小編一起看看吧2022-02-02