Qt连接并操作SQL数据库(Qt学习①)

来源:互联网 发布:线切割锥度怎样编程 编辑:程序博客网 时间:2024/05/24 03:48

初学者记录学习内容,如有错误请各位前辈指点。

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();    }

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():
1. str=QString(“%1 %2 (%3s-%4s)”)
2. 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只管列),逐次显示到界面上。

结束,如有错误,还望指正。

原创粉丝点击