使用ODBC
数据库种类繁多,由于版权原因,Qt并未包含某些数据库的驱动,比如MySQL,建议使用ODBC来取代特定数据库
ODBC,开放数据库连接,用于将不同的数据库操作转化为统一的操作接口,从而解决不同数据库之间的合作和迁移问题
以MySQL为例,我们只要安装对应的ODBC驱动( MySQL Connector ODBC),然后在操作系统中添加一个ODBC数据源,指向该数据库地址,之后我们就可以通过该ODBC数据源操作MySQL数据库
就算以后MySQL数据库更换为其它数据库,我们也只需要修改ODBC数据源即可,不需要修改代码
当然,在Qt中还有一个最大的好处,就是不用考虑不同的数据库驱动问题,由于没有自带所有主流数据库的驱动,有些驱动手动配置极其麻烦
表结构设计
本篇博客用到两个表,用户表(user)和角色表(role),用户表中的user_role通过外键引用角色表的role_id字段
//角色表
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`role_id` int(20) NOT NULL AUTO_INCREMENT,
`role_name` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
//用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`user_account` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`user_password` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`user_nickname` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`user_realname` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`org_id` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`org_name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`dept_id` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`dept_name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`user_role` int(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk` (`user_role`),
CONSTRAINT `fk` FOREIGN KEY (`user_role`) REFERENCES `role` (`role_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
打开数据库
//配置并打开数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("localhost");
db.setPort(3306);
db.setDatabaseName("animal");
db.setUserName("root");
db.setPassword("123456");
db.open();
查询数据
通过游标来迭代访问行数据,通过列索引或列名来遍历列数据
//查询数据
QSqlQuery query(db);
query.exec("select * from user");
while (query.next())
qdebug << query.value("user_id") << query.value("user_name") << query.value(2) << query.value(3);
QMessageBox::information(nullptr, "Info", "SQL Query Done");
插入数据
//插入数据
QSqlQuery query(db);
query.prepare("INSERT INTO user (user_id, user_account) VALUES (?, ?)");
query.addBindValue(QUuid::createUuid().toString());
query.addBindValue(QUuid::createUuid().toString());
query.exec();
qdebug << query.numRowsAffected() << endl;
qdebug << query.lastInsertId() << endl;
qdebug << query.lastError() << endl;
QMessageBox::information(nullptr, "Info", "SQL Insert Done");
修改数据
//修改数据
QSqlQuery query(db);
query.prepare("UPDATE user SET user_password = ?, user_nickname = ? WHERE user_password is null");
query.addBindValue(QUuid::createUuid().toString());
query.addBindValue(QUuid::createUuid().toString());
query.exec();
qdebug << query.lastQuery() << endl;
qdebug << query.numRowsAffected() << endl;
QMessageBox::information(nullptr, "Info", "SQL Update Done");
删除数据
//删除数据
QSqlQuery query(db);
query.exec("DELETE from user WHERE user_password is null");
qdebug << query.numRowsAffected() << endl;
QMessageBox::information(nullptr, "Info", "SQL Delete Done");
事务管理
//事务管理
db.transaction();
try {
// do something ...
db.commit();
} catch (...) {
db.rollback();
}
使用QSqlTableModel进行增删改查
QSqlTableModel对SQL功能进行了封装,以对象式编程风格取代SQL语法来操作数据库,可读写型更高
C++没有Java的反射功能,因此没法实现纯粹的对象式数据库框架,和SQL语法相比,优越性并不算非常大
QSqlTableModel model(nullptr, db);
//查询数据
{
model.setTable("user");
model.setFilter(QObject::tr(" id is not null and id > %1 ").arg(10));
model.select();
qdebug << model.rowCount() << endl;
for (int i = 0; i < model.rowCount(); i++) {
QSqlRecord record = model.record(i);
qdebug << record.value("id") << endl;
qdebug << record.value("user_id") << endl;
qdebug << record.value(2) << endl;
qdebug << record.value(3) << endl;
}
model.clear();
}
//插入数据
{
model.setTable("user");
QSqlRecord record = model.record();
record.setValue("user_id", QUuid::createUuid().toString());
record.setValue("user_account", QUuid::createUuid().toString());
model.insertRecord(-1, record); //-1表示在数据库末尾插入
model.clear();
}
//修改数据
//必须先查出记录,再修改提交
{
model.setEditStrategy(QSqlTableModel::OnManualSubmit);
model.setTable("user");
model.setFilter(" id = 10 ");
model.select();
for (int i = 0; i < model.rowCount(); i++)
model.setData(model.index(i, 1), "update"); //1是列索引,表示修改哪一列
model.submitAll();
model.clear();
}
//删除数据
//必须先查出记录,再删除提交
{
model.setTable("user");
model.setFilter(" id > 10 ");
model.select();
model.removeRows(0, model.rowCount());
model.submitAll();
model.clear();
}
TableView绑定SqlTableModel
QTableView可以绑定QSqlTableModel,直接显示数据库某个表格里面的数据
QTableView w;
w.show();
//配置并打开数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("localhost");
db.setPort(3306);
db.setDatabaseName("animal");
db.setUserName("root");
db.setPassword("123456");
db.open();
//查询数据
QSqlTableModel model(nullptr, db);
model.setTable("user");
model.select();
//TableView绑定SqlTableModel
model.setHeaderData(0, Qt::Horizontal, "Data Id");
model.setHeaderData(1, Qt::Horizontal, "User Id");
model.setHeaderData(2, Qt::Horizontal, "User Account");
model.setHeaderData(3, Qt::Horizontal, "User Password");
model.setHeaderData(4, Qt::Horizontal, "User Realname");
w.setModel(&model);
w.resizeColumnsToContents();
w.horizontalHeader()->setStretchLastSection(true);
w.showMaximized();
利用SqlRelationalTableModel和DataWidgetMapper实现控件和数据库复杂关联
QDataWidgetMapper可以将数据库字段与某个控件关联
QSqlRelationalTableModel可以自动查询外键关联的其它表数据
MainWindow w;
w.show();
//配置并打开数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("localhost");
db.setPort(3306);
db.setDatabaseName("animal");
db.setUserName("root");
db.setPassword("123456");
db.open();
//主数据模型
QSqlRelationalTableModel model(nullptr, db);
model.setTable("user");
model.setEditStrategy(QSqlTableModel::OnFieldChange); //数值修改,焦点切换时,自动提交修改到数据库
model.setRelation(model.fieldIndex("user_role"), QSqlRelation("role", "role_id", "role_name")); //设置外键关联
model.select(); //查询记录
//关联数据模型
//user_role已经被外键映射到role_name字段,要通过role_name来获得列索引
int roleIndex = model.fieldIndex("role_name");
QSqlTableModel* roleModel = model.relationModel(roleIndex); //获取对应字段的所有可能值,给下拉框显示
w.ui->userRoleNameCombo->setModel(roleModel);
w.ui->userRoleNameCombo->setModelColumn(roleModel->fieldIndex("role_name"));
//控件与字段绑定
QDataWidgetMapper mapper;
mapper.setSubmitPolicy(QDataWidgetMapper::AutoSubmit); //下拉数值修改时,自动提交修改到数据库
mapper.setModel(&model); //关联数据模型
mapper.setItemDelegate(new QSqlRelationalDelegate());
mapper.addMapping(w.ui->userIdEdit, model.fieldIndex("id")); //将数据映射到控件
mapper.addMapping(w.ui->userAccountEdit, model.fieldIndex("user_account"));
mapper.addMapping(w.ui->userRealnameEdit, model.fieldIndex("user_realname"));
mapper.addMapping(w.ui->userRoleNameCombo, model.fieldIndex("user_role"));
mapper.toFirst(); //显示首个记录
mapper.toNext();