一、环境准备
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::doubleclicked); // 设置数据映射器 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, "成功", "数据保存成功"); } 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. 事务处理
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增删改查的资料请关注代码网其它相关文章!
发表评论