初学者记录学习内容,如有错误请各位前辈指点。
DOS命令操作数据库
虽然在window下是可以用DOS命令建立并操作数据库,但是当涉及到一些比较复杂的数据操作的时候还是比较繁琐,这里做个简单的示例,这里对mySQL的Qt配置不做多言,贫道使用的Qt5.8已经自带配置文件了。
用DOS命令建立数据库,输入密码后,显示当前存在的数据库输入命令show databases;(命令后面一定要加“;”)
create database student;创建一个名叫student的数据库;
use student; 对数据库进行操作;
呃,黑色好难看,换个背景色,然后在数据库中创建表格,并查看表格详情。
在数据库中插入数据。
更多命令可自行查询,其实这些并没有什么卵用,不易于数据的修改,推荐使用SQL数据库可视化工具,贫道使用的是“Navicat for MySQL”。
我们在Navicat中建立表格information,用户密码设置为777777,然后就可以将Qt项目与数据库建立连接了。
Qt与SQL数据库
注意要在项目中加入数据库的应用,要先在.pro中加入sql,保存。
QT += core gui sql
连接mySQL数据库
在构造函数中加入这段代码;
QSqlDatabase dataBase=QSqlDatabase::addDatabase("QMYSQL");
dataBase.setHostName("localhost");
dataBase.setUserName("root");
dataBase.setPassword("777777");
dataBase.setDatabaseName("picturedata");
dataBase.open();
第一句是我们所加入的数据库的驱动类型,使用mySQL写入"QMYSQL",如果是使用sqlite数据库写入"QSQLITE",使用Oracle数据库写入"QOICQ" 。如上的QSqlDatabase dataBase是定义了一个数据库的句柄,又addDatabase返回并加载mySQL的驱动。数据库支持远程连接,setHostName()设置数据库主机名,这里是本地数据库。然后是setUserName()设置数据库用户名,setPassword()设置密码,setDatabaseName()设置数据库名。 这些一定要一致。
如果没有问题,连接成功以后open会返回一个bool型的变量true,我们可以接收一下这个变量qDebug显示成功或输出错误信息。
bool ok=dataBase.open();
if(ok)
{
qDebug()<<"open database success";
}
else
{
qDebug()<<"error open database because"<<this->dataBase.lastError().text();
}
这里需要注意,使用lastError()函数需要在在.h中引入
#include <QSqlError>
如果遇到
Driver not loaded的问题,其中一个解决办法是:
在H:\Qt\Qt5.5.1\5.5\mingw492_32\bin下加入SQL的动态链接库:libmysql.dll。
qDebug在项目编译初期可以这样做,但是如果不打开编译器是无法看到显示的信息的,即是说用户是无法用这种方法来判断是否连接成功的,所以可以改成用QMessageBox弹出小对话框来判断是否能够连接成功,后面会说到。
连接成功用户需要完成功能对数据库的增删改查,先看设计的界面如图:
上面的lineEdit填入数据,两个pushButton,savedataBase将数据写入数据库,resetdataBase将数据库中的数据清除,并清空界面,也就是说这个工程的数据库中始终只有一条数据。同时注意,界面打开时,lineEdit会显示数据库中存在的表信息到界面上。
插入数据
我们运行工程打开界面,在lineEdit中写入数据,点击保存,数据插入到数据库中,插入语句。
注意插入语句的语法:
INSERT INTO table_name (列1, 列2,…) VALUES (值1, 值2,…);
如下的这种方式是我认为最简单的数据库操作函数,相当于直接在Qt中书写SQL语句。
QSqlQuery query(dataBase);
QString datestr = ui->dateEdit->dateTime().toString("dd-MM-yyyy");
QString timestr = ui->dateEdit->time().toString("hh:mm:ss");
QString sql=QString("select *from information");
query.exec(sql);
if(query.numRowsAffected() == 0)
{
QString savesql = QString("INSERT INTO information(userName,IP,storagePath,productName,date)");
savesql += QString(" VALUES('%1','%2','%3','%4','%5')").arg(ui->userNameEdit->text())
.arg(ui->ipAddressEdit->text())
.arg(ui->storagePathEdit->text())
.arg(ui->productNameEdit->text())
.arg(datestr+' '+timestr);
bool ok=query.exec(savesql);
if(ok){
QMessageBox::about(NULL, "Save", "save new database success");
}
else{
QMessageBox::about(NULL, "Save", "error save new database");
}
}
在QString中写插入语句insert,当然第一行代码也可以写成这样子
QString("INSERT INTO information(userName,IP,storagePath,productName,date)
VALUES('%1','%2','%3','%4','%5')");
但是由于代码过长不便于查看最好进行拆分。在需要调用lineEdit中的输入语句时,把值写成参数”%1”””%2”……等,在后面加入.arg().arg()……;括号内可以写从控件获取文字信息的函数,或直接写入已经赋值的变量名,或者值本身。
Qt提供的一种格式化字符串输出的函数arg():
- str=QString("%1 %2 (%3s-%4s)")
- arg(“permissive”).arg(“society”).arg(1950).arg(1970);
这段代码中,%1, %2, %3, %4作为占位符,将被后面的arg()函数中的内容依次替换,比如%1将被替换成permissive,%2将被替换成society,%3将被替换成1950,%4将被替换曾1970,最后,这句代码输出为:permissive society (1950s-1970s). arg()函数比起sprintf()来是类型安全的,同时它也接受多种的数据类型作为参数,都会被转化为QString类型然后进行替换。
使用bool ok=query.exec(savesql)执行该sql语句,返回一个bool型的结果。如上面说到的,可用一个变量来接收这个结果,由结果的不同true或fulse返回不同的QMessageBox小对话来让用户得到是否执行成功。
前面的一些代码在最后一部分会有说到。
修改数据
在数据库中已经有数据的情况下,可以实现修改界面文字,点击保存,实现数据库中的值的修改,修改语句。
QString updatesql = QString("UPDATE information SET userName='%1',IP='%2',storagePath='%3',productName='%4',date='%5' WHERE IP=%6")
.arg(ui->userNameEdit->text())
.arg(ui->ipAddressEdit->text())
.arg(ui->storagePathEdit->text())
.arg(ui->productNameEdit->text())
.arg(datestr+' '+timestr)
.arg(oldIP);
bool ok=query.exec(updatesql);
if(ok){
QMessageBox::about(NULL, "Save", "save database success");}
else{
QMessageBox::about(NULL, "Save", "error save database");}
注意updata语句的语法是:
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
where之后需要给出修改的条件,如题要获取未修改的数据库中的ip的值。
贫僧之前将修改的条件设置为界面上获取的IP:
QString updatesql = QString("UPDATE information SET userName='%1',IP='%2',storagePath='%3',productName='%4',date='%5' WHERE IP=%6")
.arg(ui->userNameEdit->text())
.arg(ui->ipAddressEdit->text())
.arg(ui->storagePathEdit->text())
.arg(ui->productNameEdit->text())
.arg(datestr+' '+timestr).arg(ui->ipAddressEdit->text());
此时%6所接收到的IP是你准备要修改成的,而此时数据库中并没有的值,导致sql语句执行之后数据库中毫无变化,修改失败。可以在执行修改之前,定义一个变量oldIP去保存数据库中原来的IP值,写到主函数中。作为update语句的条件传入。
QString oldIP;
oldIP=ui->ipAddressEdit->text();
删除数据
接着实现点击刷新按钮,删除数据库中的用户信息,删除语句。
注意delete的语法是DELETE FROM 表名称 WHERE 列名称 = 值;
IP条件引用与上例相同。
QSqlQuery deletequery(dataBase);
QString deletesql = QString("DELETE FROM information WHERE IP='%1'").arg(oldIP);
bool ok=deletequery.exec(deletesql);
if(ok)
{
QMessageBox::about(NULL, "Reset", "Reset database success");
ui->userNameEdit->clear();
ui->ipAddressEdit->clear();
ui->storagePathEdit->clear();
ui->productNameEdit->clear();
ui->dateEdit->clear();
}
else
{
QMessageBox::about(NULL, "Reset", "error reset database");
}
删除数据后,需要清空lineEdit()上的数据,调用.clear();
其他的几个重点问题
判断数据库是否为空
我们再回头看插入语句的代码会发现一个问题,这里有一个问题,只有一个保存save按钮,当数据库是否为空,两种情况点击button是执行update或insert这两种哪一种sql语句呢?这里就需要加入一个判断数据库是否为空。使用select语句查询语句查找表,query.exec()运行语句。
QString sql=QString("select *from information");
query.exec(sql);
然后调用query.numRowsAffected()
int QSqlQuery::numRowsAffected () const
返回有多少行记录被结果集的 SQL语句影响了,如果不能确定将返回 -1 。注意,对于 SELECT语句,此值等同于size()如果查询处于非活动状态(isActive()返回FALSE),将反回 -1。
如果数据库为空,将有0行语句被影响,那么就执行插入语句,否则执行修改语句。
QdateTimeEdit的处理
注意界面中获取时间和日期的控件,使用的是QdateTimeEdit,从这个控件获得的数据插入到数据库中时总是出现问题,此处的是从中.dateTime()和.time()单独获取日期和时间,以dd-MM-yyyy和hh:mm:ss的形式toString();单独保存,同时传入。
QString datestr = ui->dateEdit->dateTime().toString("dd-MM-yyyy");
QString timestr = ui->dateEdit->time().toString("hh:mm:ss");
写入数据库时进行组合arg(datestr+’ '+timestr)
数据库显示到界面
如果数据库中有已插入的数据,项目执行起来时,数据会从数据库加载到lineEdit上显示到界面中,这里自然又要用到select查询语句,涉及到对执行SQL语句后返回的结果集的操作,结果集其实就是查询到的所有记录的集合,需要注意这个集合中的记录是从0开始编号的,这里使用value(int n)来获取属性的值,其中n表示你查询的第n个属性。比如value(0),返回userName的值,转化为String类型.settext()显示到lineEdit中。
关注:MySql执行之后返回的结果集指针都指向数组第一条语句之前,因此需要调用一个next(),更便于使用while循环显示,而且每执行一次该函数,便指向相邻的下一条记录。Sqllite数据库也是如此,要先调用next()。
QSqlQuery showquery(dataBase);
QString showsql=QString("select *from information");
showquery.exec(showsql);
if(showquery.numRowsAffected() != 0)
{
showquery.next();
ui->userNameEdit->setText(showquery.value(0).toString());
ui->ipAddressEdit->setText(showquery.value(1).toString());
ui->storagePathEdit->setText(showquery.value(2).toString());
ui->productNameEdit->setText(showquery.value(3).toString());
ui->dateEdit->setDateTime(QDateTime::fromString(showquery.value(4).toString(),"dd-MM-yyyy hh:mm:ss"));
}
我们注意到,数据库中始终保持了一行代码需要显示,但是如果数据库中是3×5的表,select*以后返回的结果集是个二维数组,若需要用上述的方式的显示到3×5的lineEdit中的话,可以使用while循环调用query.value();
while(query.next()){
ui->button1->setText(query.value(0).toString());
ui->button2->setText(query.value(1).toString());
ui->button3->setText(query.value(2).toString());
ui->button4->setText(query.value(3).toString());
ui->button5->setText(query.value(4).toString());
}
While语句开始执行,第一次执行query.next()后指向第一行数据,然后五次调用.value(),遍历五列数据(value只管列),逐次显示到界面上。
结束,如有错误,还望指正。