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

DOS命令操作数据库

虽然在window下是可以用DOS命令建立并操作数据库,但是当涉及到一些比较复杂的数据操作的时候还是比较繁琐,这里做个简单的示例,这里对mySQL的Qt配置不做多言,贫道使用的Qt5.8已经自带配置文件了。

用DOS命令建立数据库,输入密码后,显示当前存在的数据库输入命令show databases;(命令后面一定要加“;”)

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_数据库


create database student;创建一个名叫student的数据库;

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_mysql_02


use student; 对数据库进行操作;

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_数据库_03


呃,黑色好难看,换个背景色,然后在数据库中创建表格,并查看表格详情。

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_QT5连接MYSQL数据库的驱动_04


在数据库中插入数据。

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_QT5连接MYSQL数据库的驱动_05


更多命令可自行查询,其实这些并没有什么卵用,不易于数据的修改,推荐使用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>

如果遇到

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_sql_06


Driver not loaded的问题,其中一个解决办法是:

在H:\Qt\Qt5.5.1\5.5\mingw492_32\bin下加入SQL的动态链接库:libmysql.dll。

qDebug在项目编译初期可以这样做,但是如果不打开编译器是无法看到显示的信息的,即是说用户是无法用这种方法来判断是否连接成功的,所以可以改成用QMessageBox弹出小对话框来判断是否能够连接成功,后面会说到。

连接成功用户需要完成功能对数据库的增删改查,先看设计的界面如图:

QT5连接MYSQL数据库的驱动 qt连接数据库并添加数据_QT5连接MYSQL数据库的驱动_07


上面的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只管列),逐次显示到界面上。

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