/*******************************************************************************************/
一、数据库连接
Qt 提供了 QtSql 模块来提供平台独立的基于 SQL 的数据库操作。这里我们所说的“平台独立”,既包括操作系统平台,
有包括各个数据库平台。另外,我们强调了“基于 SQL”,因为 NoSQL 数据库至今没有一个通用查询方法,
所以不可能提供一种通用的 NoSQL 数据库的操作。Qt 的数据库操作还可以很方便的与 model/view 架构进行整合。
通常来说,我们对数据库的操作更多地在于对数据库表的操作,而这正是 model/view 架构的长项。
Qt 使用QSqlDatabase表示一个数据库连接。更底层上,Qt 使用驱动(drivers)来与不同的数据库 API 进行交互。
Qt 桌面版本提供了如下几种驱动:
驱动 数据库
QDB2 IBM DB2 (7.1 或更新版本)
QIBASE Borland InterBase
QMYSQL MySQL
QOCI Oracle Call Interface Driver
QODBC Open Database Connectivity (ODBC) – Microsoft SQL Server 及其它兼容 ODBC 的数据库
QPSQL PostgreSQL (7.3 或更新版本)
QSQLITE2 SQLite 2
QSQLITE SQLite 3
QSYMSQL 针对 Symbian 平台的SQLite 3
QTDS Sybase Adaptive Server (自 Qt 4.7 起废除)
不过,由于受到协议的限制,Qt 开源版本并没有提供上面所有驱动的二进制版本,而仅仅以源代码的形式提供。
通常,Qt 只默认搭载 QSqlite 驱动(这个驱动实际还包括 Sqlite 数据库,也就是说,如果需要使用 Sqlite 的话,只需要该驱动即可)。
我们可以选择把这些驱动作为 Qt 的一部分进行编译,也可以当作插件编译。
如果习惯于使用 SQL 语句,我们可以选择QSqlQuery类;如果只需要使用高层次的数据库接口(不关心 SQL 语法),
我们可以选择使用QsqlTableModel类。
在使用时,我们可以通过
QSqlDatabase::drivers();
找到系统中所有可用的数据库驱动的名字列表。我们只能使用出现在列表中的驱动。
1.操作数据库的依赖
使用数据库的时候,需要加入数据库的库文件,比如mysql:
如果没有在项目中加入mysql的库(需要自己去下载然后添加,比如window的libmysql.dll),就会提示驱动没有加载的错误
数据库库文件(libmysql.dll)需要放到qt的安装目录里面的bin目录下
2.项目配置文件的修改
使用数据库时,需要在项目文件中加上:
QT += sql
3.数据库连接代码
#include <QSqlDatabase>
//打印Qt支持的数据库驱动
qDebug() << QSqlDatabase::drivers();
可以得知,qt支持的数据库:
sqllite 静态数据库,不需要服务器,类似文件那样,保存的是.db的文件,但是操作是数据的操作方式
开源,提供.h .c文件,文件型数据库
mysql
obdc windows提供好的一个数据库操作库,封装好,不需要sql语句都可以操作
psql
现在用mysql举例:
//添加MySql数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
//连接数据库
db.setHostName("127.0.0.1"); //数据库服务器IP 端口默认是3236,不需要设置
db.setUserName("root"); //数据库用户名
db.setPassword("123456"); //密码
db.setDatabaseName("info"); //使用哪个数据库,mysql中创建的数据库
//打开数据库
if( !db.open() ) //数据库打开失败
{//如果没有在项目中加入mysql的库(需要自己去下载然后添加,比如window的libmysql.dll),就会提示驱动没有加载的错误
QMessageBox::warning(this, "错误", db.lastError().text());//此时需要,数据库库文件(libmysql.dll)需要放到qt的安装目录里面的bin目录下
return;
}
/*******************************************************************************************/
二、数据库插入
#include <QSqlQuery>//执行sql语句需要的头文件
QSqlQuery query;//只操作一个数据库时不需要传入数据库对象
query.exec("create table student(id int primary key, name varchar(255), age int, score int);");
//这样创建对象后,传入sql语句就可以操作了
1.当需要操作多个数据库(Database)时,有两点需要注意:
1).创建数据库对象时,需要传入标识,用来区分创建出来的数据库和其他的不同
QSqlDatabase db1 = QSqlDatabase::addDatabase("QMYSQL", "a");
2).操作数据时,需要传入数据库对象,来指明是哪个数据库。同时如果前面创建给了标识,则
这里创建查询对象时必须传入数据库对象,否则操作将不成功
QSqlQuery query1(db1);
query1.exec("create table student(id int primary key, name varchar(255), age int, score int);");
2.插入
QSqlQuery query;
query.exec("insert into student(id, name, age, score) values(1, 'mike', 18, 59);");
3.批量插入,有两种方式:
1).odbc(windows)风格
预处理语句
? 相当于 占位符
query.prepare("insert into student(name, age, score) values(?, ?, ?)");
给字段设置内容 通过list,list可以放任何类型
QVariantList nameList;
nameList << "xiaoming" << "xiaolong" << "xiaojiang";
QVariantList ageList;
ageList << 11 << 22 << 33;
QVariantList scoreList;
scoreList << 59 << 69 << 79;
给字段绑定相应的值 按顺序绑定,否则插入不成功
query.addBindValue(nameList);
query.addBindValue(ageList);
query.addBindValue(scoreList);
执行预处理命令
query.execBatch();
2).oracle风格
预处理语句
占位符 : + 自定义名字
query.prepare("insert into student(name, age, score) values(:name, :age, :score)");
给字段设置内容 list
QVariantList nameList;
nameList << "xiaoa" << "xiaob" << "xiaoc";
QVariantList ageList;
ageList << 33 << 44 << 55;
QVariantList scoreList;
scoreList << 89 << 90 << 99;
给字段绑定,有标识符指定了,所以不局限于顺序
query.bindValue(":name", nameList);
query.bindValue(":score", scoreList);
query.bindValue(":age", ageList);
执行预处理命令
query.execBatch();
/*******************************************************************************************/
三、数据库删除和遍历
1.删除
//开启一个事务,
QSqlDatabase::database().transaction();//QSqlDatabase::database()获取数据库然后调用开启事务函数
//确定删除
QSqlDatabase::database().commit();
//回滚,撤销
QSqlDatabase::database().rollback();
2.遍历(查找所有):
查询返回结果不包括字段,从第一行记录开始,即第0个为第一条记录
QSqlQuery query;
query.exec("select * from student");//如果只是查一行,sql中加上where条件过滤即可
while(query.next()) //一行一行遍历,执行完自动跳到下一行,从第一行记录开始
{
//取出当前行的内容,取的时候以列为单位,第0列即第一列id,除了用下标来取之外还可以用字段名来取值
qDebug() << query.value(0).toInt()
<< query.value(1).toString()
<< query.value("age").toInt()
<< query.value("score").toInt();
}
上述代码具体见《Database》
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 6 namespace Ui { 7 class Widget; 8 } 9 10 class Widget : public QWidget 11 { 12 Q_OBJECT 13 14 public: 15 explicit Widget(QWidget *parent = 0); 16 ~Widget(); 17 18 private slots: 19 void on_buttonDel_clicked(); 20 21 void on_buttonSure_clicked(); 22 23 void on_buttonCancel_clicked(); 24 25 private: 26 Ui::Widget *ui; 27 }; 28 29 #endif // WIDGET_H
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QSqlDatabase> 4 #include <QDebug> 5 #include <QMessageBox> 6 #include <QSqlError> 7 #include <QSqlQuery> 8 #include <QVariantList> 9 10 Widget::Widget(QWidget *parent) : 11 QWidget(parent), 12 ui(new Ui::Widget) 13 { 14 ui->setupUi(this); 15 16 //打印Qt支持的数据库驱动 17 qDebug() << QSqlDatabase::drivers(); 18 19 //添加MySql数据库 20 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); 21 22 //连接数据库 23 db.setHostName("127.0.0.1"); //数据库服务器IP 24 db.setUserName("root"); //数据库用户名 25 db.setPassword("123456"); //密码 26 db.setDatabaseName("info"); //使用哪个数据库 27 28 29 //打开数据库 30 if( !db.open() ) //数据库打开失败 31 { 32 QMessageBox::warning(this, "错误", db.lastError().text()); 33 return; 34 } 35 36 // QSqlQuery query; 37 // query.exec("create table student(id int primary key, name varchar(255), age int, score int);"); 38 39 40 /* 41 QSqlDatabase db1 = QSqlDatabase::addDatabase("QMYSQL", "a"); 42 db1.setHostName("127.0.0.1"); //数据库服务器IP 43 db1.setUserName("root"); //数据库用户名 44 db1.setPassword("123456"); //密码 45 db1.setDatabaseName("test"); //使用哪个数据库 46 47 //打开数据库 48 if( !db1.open() ) //数据库打开失败 49 { 50 QMessageBox::warning(this, "错误", db.lastError().text()); 51 return; 52 } 53 54 QSqlQuery query1; 55 query1.exec("create table student(id int primary key, name varchar(255), age int, score int);"); 56 */ 57 58 //插入 59 //QSqlQuery query; 60 // query.exec("insert into student(id, name, age, score) values(1, 'mike', 18, 59);"); 61 62 //批量插入 63 //odbc风格 64 //预处理语句 65 // ? 相当于 占位符 66 // query.prepare("insert into student(name, age, score) values(?, ?, ?)"); 67 // //给字段设置内容 list 68 // QVariantList nameList; 69 // nameList << "xiaoming" << "xiaolong" << "xiaojiang"; 70 // QVariantList ageList; 71 // ageList << 11 << 22 << 33; 72 // QVariantList scoreList; 73 // scoreList << 59 << 69 << 79; 74 // //给字段绑定相应的值 按顺序绑定 75 // query.addBindValue(nameList); 76 // query.addBindValue(ageList); 77 // query.addBindValue(scoreList); 78 // //执行预处理命令 79 // query.execBatch(); 80 81 //oracle风格 82 //占位符 : + 自定义名字 83 // query.prepare("insert into student(name, age, score) values(:name, :age, :score)"); 84 // //给字段设置内容 list 85 // QVariantList nameList; 86 // nameList << "xiaoa" << "xiaob" << "xiaoc"; 87 // QVariantList ageList; 88 // ageList << 33 << 44 << 55; 89 // QVariantList scoreList; 90 // scoreList << 89 << 90 << 99; 91 // //给字段绑定 92 // query.bindValue(":name", nameList); 93 // query.bindValue(":score", scoreList); 94 // query.bindValue(":age", ageList); 95 96 // //执行预处理命令 97 // query.execBatch(); 98 99 QSqlQuery query; 100 query.exec("select * from student"); 101 102 while(query.next()) //一行一行遍历 103 { 104 //取出当前行的内容 105 qDebug() << query.value(0).toInt() 106 << query.value(1).toString() 107 << query.value("age").toInt() 108 << query.value("score").toInt(); 109 } 110 111 112 } 113 114 Widget::~Widget() 115 { 116 delete ui; 117 } 118 119 void Widget::on_buttonDel_clicked() 120 { 121 //获取行编辑内容 122 QString name = ui->lineEdit->text(); 123 124 125 QString sql = QString("delete from student where name = '%1'").arg(name); 126 127 //开启一个事务 128 QSqlDatabase::database().transaction(); 129 QSqlQuery query; 130 query.exec(sql); 131 132 } 133 134 void Widget::on_buttonSure_clicked() 135 { 136 //确定删除 137 QSqlDatabase::database().commit(); 138 } 139 140 void Widget::on_buttonCancel_clicked() 141 { 142 //回滚,撤销 143 QSqlDatabase::database().rollback(); 144 }
/*******************************************************************************************/
四、sqlite
sqlite是本地数据库,不需要链接
//添加Sqlite数据库
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//设置数据库
db.setDatabaseName("../info.db");//注意整个.db文件可以自己新建一个文本文件然后重命名即可
后面都一样,注意,自动累加auto_increment,sqlite不支持。
上述代码具体见《SqlLite》
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 6 namespace Ui { 7 class Widget; 8 } 9 10 class Widget : public QWidget 11 { 12 Q_OBJECT 13 14 public: 15 explicit Widget(QWidget *parent = 0); 16 ~Widget(); 17 18 private: 19 Ui::Widget *ui; 20 }; 21 22 #endif // WIDGET_H
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QSqlDatabase> 4 #include <QDebug> 5 #include <QMessageBox> 6 #include <QSqlError> 7 #include <QSqlQuery> 8 #include <QVariantList> 9 10 Widget::Widget(QWidget *parent) : 11 QWidget(parent), 12 ui(new Ui::Widget) 13 { 14 ui->setupUi(this); 15 16 //打印Qt支持的数据库驱动 17 qDebug() << QSqlDatabase::drivers(); 18 19 //添加Sqlite数据库 20 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); 21 //设置数据库 22 db.setDatabaseName("../info.db"); 23 24 //打开数据库 25 if( !db.open() ) //数据库打开失败 26 { 27 QMessageBox::warning(this, "错误", db.lastError().text()); 28 return; 29 } 30 31 QSqlQuery query; 32 query.exec("create table student(id int primary key, name varchar(255), age int, score int);"); 33 34 query.prepare("insert into student(name, age, score) values(?, ?, ?)"); 35 //给字段设置内容 list 36 QVariantList nameList; 37 nameList << "xiaoming" << "xiaolong" << "xiaojiang"; 38 QVariantList ageList; 39 ageList << 11 << 22 << 33; 40 QVariantList scoreList; 41 scoreList << 59 << 69 << 79; 42 //给字段绑定相应的值 按顺序绑定 43 query.addBindValue(nameList); 44 query.addBindValue(ageList); 45 query.addBindValue(scoreList); 46 //执行预处理命令 47 query.execBatch(); 48 49 query.exec("select * from student"); 50 51 while(query.next()) //一行一行遍历 52 { 53 //取出当前行的内容 54 qDebug() << query.value(0).toInt() 55 << query.value(1).toString() 56 << query.value("age").toInt() 57 << query.value("score").toInt(); 58 } 59 60 61 62 } 63 64 Widget::~Widget() 65 { 66 delete ui; 67 }
/*******************************************************************************************/
五、可视化操作数据库
Qt 不仅提供了这种使用 SQL 语句的方式,还提供了一种基于模型的更高级的处理方式。这种基于QSqlTableModel 的模型处理更为高级,
如果对 SQL 语句不熟悉,并且不需要很多复杂的查询,这种QSqlTableModel模型基本可以满足一般的需求。
即使用可以不懂sql语句都可以操作的类,来操作数据库
model/view 架构:
ModelView 模型视图
Model 单独一个类,只做一件事情,存储数据
view 单独一个类,只做一件事情,显示和修改数据
使用ui中的Item Views中的Table View
1.使用模型操作数据库
#include <QSqlTableModel>//表格的模型
//设置模型
model = new QSqlTableModel(this);
model->setTable("student");//自动和数据库关联上了,但是还需要指定使用哪个表
//把model放在view,如果没有放进去,则model只是可以操作数据并不会显示出来
ui->tableView->setModel(model);//但是此时里面还没有数据,需要model来显示数据
//显示model里的数据
model->select();//这样就把表中所有的数据显示成表格的样子在窗口中
//此时修改窗口中表格的数据,数据库里面的内容也会随之改动
另外需要注意,由于QSqlTableModel只是一种高级操作,肯定没有实际 SQL 语句方便。
具体来说,我们使用QSqlTableModel只能进行 SELECT * 的查询,不能只查询其中某些列的数据。
设置model一些属性:
修改字段的显示效果
model->setHeaderData(0, Qt::Horizontal, "学号");//水平方向第0列即id显示为汉字学号
设置model的编辑模式,手动提交修改,修改后需要确定后才会修改到数据库
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
设置view中的数据库不允许修改,只是显示数据里面的内容。//表现为双击不会让用户修改的现象
ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
2.可视化增加一条记录:
//添加空记录
QSqlRecord record = model->record(); //获取空记录,传入标号后就是获取某一行
//获取行号
int row = model->rowCount();
model->insertRecord(row, record);//在指定行插入空记录,这是界面上就会出现一个空行,
//用户就可以在空行里面填入输入,填入好后就实现了增加记录
3.可视化提交:
model->submitAll(); //提交动作
4.可视化回滚:
model->revertAll(); //取消所有动作
model->submitAll(); //提交动作,//取消也是动作,要生效还得提交一次
5.可视化删除,注意可以选中多行删除(需要用到模型的概念:选中的多行就形成一个模型):
//获取选中的模型
QItemSelectionModel *sModel =ui->tableView->selectionModel();
//取出模型中的索引(每条记录的索引集合)
QModelIndexList list = sModel->selectedRows();
//删除所有选中的行
for(int i = 0; i < list.size(); i++)
{
model->removeRow( list.at(i).row() );//传入记录的行号
}
6.可视化查找(以通过名字查找举例):
QString name = ui->lineEdit->text();
QString str = QString("name = '%1'").arg(name);//过滤条件格式,注意字符串不能少了单引号
model->setFilter(str);//设定过滤条件
model->select();//过滤完后显示一下
上述代码具体见《ModelView》
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 #include <QSqlTableModel> 6 7 namespace Ui { 8 class Widget; 9 } 10 11 class Widget : public QWidget 12 { 13 Q_OBJECT 14 15 public: 16 explicit Widget(QWidget *parent = 0); 17 ~Widget(); 18 19 private slots: 20 void on_buttonAdd_clicked(); 21 22 void on_buttonSure_clicked(); 23 24 void on_buttonCancel_clicked(); 25 26 void on_buttonDel_clicked(); 27 28 void on_buttonFind_clicked(); 29 30 private: 31 Ui::Widget *ui; 32 QSqlTableModel *model; 33 }; 34 35 #endif // WIDGET_H
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QSqlDatabase> 4 #include <QDebug> 5 #include <QMessageBox> 6 #include <QSqlError> 7 #include <QSqlTableModel> 8 #include <QSqlRecord> 9 10 Widget::Widget(QWidget *parent) : 11 QWidget(parent), 12 ui(new Ui::Widget) 13 { 14 ui->setupUi(this); 15 16 //打印Qt支持的数据库驱动 17 qDebug() << QSqlDatabase::drivers(); 18 19 //添加MySql数据库 20 QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); 21 22 //连接数据库 23 db.setHostName("127.0.0.1"); //数据库服务器IP 24 db.setUserName("root"); //数据库用户名 25 db.setPassword("123456"); //密码 26 db.setDatabaseName("info"); //使用哪个数据库 27 28 29 //打开数据库 30 if( !db.open() ) //数据库打开失败 31 { 32 QMessageBox::warning(this, "错误", db.lastError().text()); 33 return; 34 } 35 36 //设置模型 37 model = new QSqlTableModel(this); 38 model->setTable("student");//制定使用哪个表 39 40 //把model放在view 41 ui->tableView->setModel(model); 42 43 //显示model里的数据 44 model->select(); 45 46 model->setHeaderData(0, Qt::Horizontal, "学号"); 47 48 //设置model的编辑模式,手动提交修改 49 model->setEditStrategy(QSqlTableModel::OnManualSubmit); 50 51 //设置view中的数据库不允许修改 52 //ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); 53 54 } 55 56 Widget::~Widget() 57 { 58 delete ui; 59 } 60 61 void Widget::on_buttonAdd_clicked() 62 { 63 //添加空记录 64 QSqlRecord record = model->record(); //获取空记录 65 //获取行号 66 int row = model->rowCount(); 67 model->insertRecord(row, record); 68 69 70 } 71 72 void Widget::on_buttonSure_clicked() 73 { 74 model->submitAll(); //提交动作 75 } 76 77 void Widget::on_buttonCancel_clicked() 78 { 79 model->revertAll(); //取消所用动作 80 model->submitAll(); //提交动作 81 } 82 83 void Widget::on_buttonDel_clicked() 84 { 85 //获取选中的模型 86 QItemSelectionModel *sModel =ui->tableView->selectionModel(); 87 //取出模型中的索引 88 QModelIndexList list = sModel->selectedRows(); 89 //删除所有选中的行 90 for(int i = 0; i < list.size(); i++) 91 { 92 model->removeRow( list.at(i).row() ); 93 } 94 95 } 96 97 void Widget::on_buttonFind_clicked() 98 { 99 QString name = ui->lineEdit->text(); 100 QString str = QString("name = '%1'").arg(name); 101 102 model->setFilter(str); 103 model->select(); 104 105 }