查看: 79|回复: 0

[PostgreSQL] QT操作PostgreSQL数据库并实现增删改查功能

[复制链接]

0

主题

0

回帖

0

积分

积极分子

金币
0
阅读权限
220
精华
0
威望
0
贡献
0
在线时间
0 小时
注册时间
2010-11-9
发表于 2025-5-15 08:58:08 | 显示全部楼层 |阅读模式

一、环境准备

1. 安装 PostgreSQL

确保已安装 PostgreSQL 并创建了测试数据库。

2. 安装 Qt 开发环境

确保已安装 Qt 开发环境(Qt Creator 或命令行工具)。

3. 配置 Qt 连接 PostgreSQL

在项目文件(.pro)中添加:

QT += sql

二、连接 PostgreSQL 数据库

1. 基本连接方式

#include <QCoreApplication>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlError>
#include <QDebug>
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    // 创建数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
    
    // 设置连接参数
    db.setHostName("localhost");      // 主机名
    db.setPort(5432);                 // 端口
    db.setDatabaseName("testdb");     // 数据库名
    db.setUserName("postgres");       // 用户名
    db.setPassword("password");       // 密码
    
    // 打开连接
    if (!db.open()) {
        qDebug() << "数据库连接失败:" << db.lastError().text();
        return -1;
    }
    
    qDebug() << "成功连接到数据库";
    
    // 关闭连接
    db.close();
    
    return a.exec();
}

2. 使用连接池(推荐)

// 创建连接池
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() << "创建连接池失败:" << 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);
}

三、实现增删改查操作

1. 创建测试表

首先在 PostgreSQL 中创建测试表:

CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    position VARCHAR(50),
    salary NUMERIC(10, 2),
    hire_date DATE
);

2. 插入数据(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() << "插入数据失败:" << query.lastError().text();
        return false;
    }
    
    return true;
}

3. 查询数据(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();
    
    // 设置表头
    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. 更新数据(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. 删除数据(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() << "数据库连接失败:" << 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;
    }
    
    // 插入数据
    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", "开发工程师");
    query.bindValue(":salary", 15000.00);
    query.bindValue(":hire_date", QDate::currentDate());
    
    if (!query.exec()) {
        qDebug() << "插入失败:" << query.lastError().text();
    } else {
        qDebug() << "插入成功,ID:" << query.lastInsertId().toInt();
    }
    
    // 查询数据
    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();
    }
    
    // 更新数据
    query.prepare("UPDATE employees SET salary = :salary WHERE id = :id");
    query.bindValue(":salary", 16000.00);
    query.bindValue(":id", 1); // 假设ID为1的员工
    
    if (!query.exec()) {
        qDebug() << "更新失败:" << query.lastError().text();
    } else {
        qDebug() << "更新成功";
    }
    
    // 删除数据
    query.prepare("DELETE FROM employees WHERE id = :id");
    query.bindValue(":id", 1); // 假设要删除ID为1的员工
    
    if (!query.exec()) {
        qDebug() << "删除失败:" << query.lastError().text();
    } else {
        qDebug() << "删除成功";
    }
    
    closeDatabase(db);
    return a.exec();
}

2. 使用Qt Widgets实现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);
 
    // 连接数据库
    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, "错误", "无法连接到数据库: " + db.lastError().text());
        return;
    }
 
    // 创建模型
    model = new QSqlTableModel(this, db);
    model->setTable("employees");
    model->select();
 
    // 设置表头
    model->setHeaderData(1, Qt::Horizontal, tr("姓名"));
    model->setHeaderData(2, Qt::Horizontal, tr("职位"));
    model->setHeaderData(3, Qt::Horizontal, tr("薪资"));
    model->setHeaderData(4, Qt::Horizontal, tr("入职日期"));
 
    // 设置视图
    ui->tableView->setModel(model);
    ui->tableView->setEditTriggers(QAbstractItemView:oubleClicked);
 
    // 设置数据映射器
    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 &current, const QModelIndex &) {
                mapper->setCurrentModelIndex(current);
            });
}
 
EmployeeForm::~EmployeeForm()
{
    delete ui;
}
 
void EmployeeForm:n_addButton_clicked()
{
    int row = model->rowCount();
    model->insertRow(row);
    ui->tableView->selectRow(row);
    mapper->setCurrentIndex(row);
    ui->nameEdit->setFocus();
}
 
void EmployeeForm:n_saveButton_clicked()
{
    if (!model->submitAll()) {
        QMessageBox::warning(this, "错误", "保存失败: " + model->lastError().text());
    } else {
        model->database().transaction();
        if (model->submitAll()) {
            model->database().commit();
            QMessageBox::information(this, "成功", "数据保存成功");
        } else {
            model->database().rollback();
            QMessageBox::warning(this, "错误", "保存失败: " + model->lastError().text());
        }
    }
}
 
void EmployeeForm:n_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:n_refreshButton_clicked()
{
    model->select();
}

五、高级功能

1. 事务处理

bool performTransaction(QSqlDatabase &db) {
    db.transaction();
    
    QSqlQuery query(db);
    bool success = true;
    
    // 执行多个操作
    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() << "调用存储过程失败:" << query.lastError().text();
        return false;
    }
    
    return true;
}

六、常见问题解决

1. 连接失败

  • 检查PostgreSQL服务是否运行
  • 验证连接参数(主机名、端口、数据库名、用户名、密码)
  • 检查防火墙设置
  • 确保安装了PostgreSQL客户端库

2. 中文乱码

// 设置编码
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));

或者在连接字符串中指定编码:

db.setConnectOptions("client_encoding=UTF8");

3. 性能优化

  • 使用预处理语句
  • 批量操作代替单条操作
  • 合理使用事务
  • 为常用查询创建索引

七、总结

Qt 提供了强大而灵活的数据库访问功能,通过 Qt SQL 模块可以轻松实现 PostgreSQL 数据库的增删改查操作。本文介绍了从基本连接到高级功能的实现方法,并提供了完整的代码示例。在实际开发中,可以根据项目需求选择合适的实现方式,结合事务处理、批量操作等技术提高应用性能。

以上就是QT操作PostgreSQL数据库并实现增删改查功能的详细内容,更多关于QT操作PostgreSQL增删改查的资料请关注琼殿技术社区其它相关文章!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部