QT操作PostgreSQL數(shù)據(jù)庫并實(shí)現(xiàn)增刪改查功能
一、環(huán)境準(zhǔn)備
1. 安裝 PostgreSQL
確保已安裝 PostgreSQL 并創(chuàng)建了測試數(shù)據(jù)庫。
2. 安裝 Qt 開發(fā)環(huán)境
確保已安裝 Qt 開發(fā)環(huán)境(Qt Creator 或命令行工具)。
3. 配置 Qt 連接 PostgreSQL
在項(xiàng)目文件(.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"); // 主機(jī)名
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);
}三、實(shí)現(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);
// 使用預(yù)處理語句防止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實(shí)現(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, "確認(rèn)", "確定要刪除這條記錄嗎?",
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í)行多個(gè)操作
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ù)是否運(yùn)行
- 驗(yàn)證連接參數(shù)(主機(jī)名、端口、數(shù)據(jù)庫名、用戶名、密碼)
- 檢查防火墻設(shè)置
- 確保安裝了PostgreSQL客戶端庫
2. 中文亂碼
// 設(shè)置編碼
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));或者在連接字符串中指定編碼:
db.setConnectOptions("client_encoding=UTF8");3. 性能優(yōu)化
- 使用預(yù)處理語句
- 批量操作代替單條操作
- 合理使用事務(wù)
- 為常用查詢創(chuàng)建索引
七、總結(jié)
Qt 提供了強(qiáng)大而靈活的數(shù)據(jù)庫訪問功能,通過 Qt SQL 模塊可以輕松實(shí)現(xiàn) PostgreSQL 數(shù)據(jù)庫的增刪改查操作。本文介紹了從基本連接到高級功能的實(shí)現(xiàn)方法,并提供了完整的代碼示例。在實(shí)際開發(fā)中,可以根據(jù)項(xiàng)目需求選擇合適的實(shí)現(xiàn)方式,結(jié)合事務(wù)處理、批量操作等技術(shù)提高應(yīng)用性能。
以上就是QT操作PostgreSQL數(shù)據(jù)庫并實(shí)現(xiàn)增刪改查功能的詳細(xì)內(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-12
postgresql如何查詢重復(fù)計(jì)數(shù)及去重查詢
這篇文章主要介紹了postgresql如何查詢重復(fù)計(jì)數(shù)及去重查詢問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
sqoop 實(shí)現(xiàn)將postgresql表導(dǎo)入hive表
這篇文章主要介紹了sqoop 實(shí)現(xiàn)將postgresql表導(dǎo)入hive表,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
PostgreSQL中date_trunc函數(shù)的語法及一些示例
這篇文章主要給大家介紹了關(guān)于PostgreSQL中date_trunc函數(shù)的語法及一些示例的相關(guān)資料,DATE_TRUNC函數(shù)是PostgreSQL數(shù)據(jù)庫中用于截?cái)嗳掌诓糠值暮瘮?shù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04
PostgreSQL標(biāo)準(zhǔn)建表語句分享
這篇文章主要介紹了PostgreSQL標(biāo)準(zhǔn)建表語句分享,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Postgresql根據(jù)響應(yīng)數(shù)據(jù)反向?qū)崿F(xiàn)建表語句與insert語句的過程
根據(jù)已有數(shù)據(jù),可構(gòu)建名為products的表,包含id(自增主鍵)、title(非空字符串)、progress(非空整數(shù))三個(gè)字段,建表后,可通過insert語句插入數(shù)據(jù),這種反向操作有助于從現(xiàn)有數(shù)據(jù)結(jié)構(gòu)出發(fā),快速構(gòu)建數(shù)據(jù)庫表,并進(jìn)行數(shù)據(jù)填充,感興趣的朋友跟隨小編一起看看吧2022-02-02

