一、简介

1.数据库简介

       Qt本身并不包含数据库,但是可以通过Qt操作市面上主流的数据库产品,并且Qt为这些数据库的操作设计了统一的操作接口。
支持的数据库产品有:

       Qt使用这些数据库都需要在计算机中分别安装对应的数据库产品,但是由于SQLite数据库本身体积较小,因此Qt中集成了SQLite数据库和对应的驱动程序,可以直接使用。

2.类的简介

        数据库相关类的使用需要在.pro项目配置文件中增加sql模块。

  本次使用的相关类有:
        ●QSqlDatabase
            数据库连接类,表示一个数据库的连接。
        ●QSqlError
            数据库错误信息类,内部包含了数据库底层传递到Qt中的错误信息。
        ●QSqlQuery
            数据库操作类,用于执行 SQL语句。

二、连接和关闭数据库

相关函数如下:

// 获得一个数据库连接对象
// 参数:数据库的类型,SQLite3数据库对应的类型是"QSQLITE"
// 返回值:数据库连接对象
QSqlDatabase QSqlDatabase::addDatabase(const QString & type) [static]
// 如果使用的是SQLite数据库,此函数表示设置的是数据库文件的名称,数据库文件会在项目的构建目录中生成
// 参数:数据库文件名称,SQLite数据库文件的格式通常是.db或.db3
void QSqlDatabase::setDatabaseName(const QString & name)
// 打开数据库连接
// 返回值是打开连接的结果
bool QSqlDatabase::open()
// 返回上一次数据库出错的错误信息
QSqlError QSqlDatabase::lastError() const
// 返回错误信息的字符串
QString QSqlError::text() const
//关闭数据库连接
//sqlite本质上是文件操作,Qt程序结束时任何打开的文件是会关掉的,但是最好要在程序中关闭连接。
void QSqlDatabase::close()

       连接成功后会在构建目录里会生成数据库文件。

 三、建表

一个可参考的建表语句(本文设计的是水果管理系统)如下所示:

CREATE TABLE fruit(
    id    INTEGER PRIMARY KEY,
    name  TEXT,
    loc   TEXT,
    price REAL); 

相关函数如下:

// 执行SQL语句
// 参数:要执行的SQL语句
// 返回值:执行的结果
bool QSqlQuery::exec(const QString & query)
// 返回当前操作类对象的上一个执行错误信息
QSqlError QSqlQuery::lastError() const

       建表完成后,可以使用SQLiteSpy程序直接打开.db文件,观察内部的表结构是否与预设一致,检验建表操作是否成功。

 四、增删改

       插入数据需要先获取用户输入,把用户输入的数据组成对应SQL语句执行。Qt中不建议使用字符串拼接的方式组成最终的SQL语句,因为:
        ●会降低代码的安全性,可能引发SQL注入问题
        ●拼接字符串容易出错
      Qt中推荐使用SQL预处理+参数绑定的方式,分为三步:
      1. 先编写一个预处理的SQL语句,在这个SQL语句中需要参数的位置使用占位符替换,占位符有两种编写方式:

        ●Oracle风格
            占位符使用 :列名
            这种风格的缺点是代码编写繁琐,优点是参数绑定时可以乱序。
        ●ODBC风格
            占位符使用英文问号 ?
            这种风格的优点是代码编写简单,缺点是参数绑定时必须按照顺序。

// 预处理函数
// 参数为要预处理的SQL语句
// 返回值为预处理的结果
bool QSqlQuery::prepare(const QString & query)

       2. 调用函数进行参数绑定,把参数绑定到第一步占位符的位置。

// Oracle风格的参数绑定函数
// 参数1::列名
// 参数2:参数1对应的绑定数据
void QSqlQuery::bindValue(const QString & placeholder, 
                          const QVariant & val)
// ODBC风格的参数绑定函数
// 参数为QVariant类型,表示支持常见的Qt数据类型
void QSqlQuery::addBindValue(const QVariant & val)

        3. 执行绑定后的SQL语句。

// 执行之前预处理的SQL语句,注意不要传递参数,如果传递参数,表示执行参数对应的SQL语句
// 返回值:执行的结果
bool QSqlQuery::exec()

       插入操作执行后,同样可以通过SQLiteSpy打开数据文件,双击表名可以查询表中内容进行验证。

 五、查询

模糊查询使用关键字LIKE配合两个通配符实现:
●%
任意多个(0,1,......,n)字符。
●_
任意一个字符

 相关函数如下:

// 尝试获得下个记录的数据,如果成功则移动游标并返回true;如果失败返回false
bool QSqlQuery::next()
// 取得当前游标指向的记录的某一列数据
// 参数:列序号
// 返回值:QVariant类型,可以根据所需转换为对应类型
QVariant QSqlQuery::value(int index) const
// 取得当前游标指向的记录的某一列数据
// 参数:列名
// 返回值:QVariant类型,可以根据所需转换为对应类型
QVariant QSqlQuery::value(const QString & name) const

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QMessageBox>
#include <QButtonGroup>
// 数据库连接类
#include <QSqlDatabase>
#include <QDebug>
// 数据库错误信息类
#include <QSqlError>
// 数据库操作类
#include <QSqlQuery>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    Ui::Dialog *ui;
    QButtonGroup *group;
    void connect2DB(); // 连接到数据库
    QSqlDatabase db; // 数据库连接类对象
    void createTable(); // 建表
    void insertData(); // 插入数据
    void deleteData(); // 删除数据
    void updateData(); // 更改数据
    void selectAll(); // 查询所有数据
    bool isDataExists(int); // 判断某个id的数据在不在
    void selectLike(); // 模糊查询

private slots:
    void btnsClickedSlot(int);
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    group = new QButtonGroup(this);
    group->addButton(ui->pushButtonInsert,1);
    group->addButton(ui->pushButtonDelete,2);
    group->addButton(ui->pushButtonUpdate,3);
    group->addButton(ui->pushButtonSelect,4);

    connect(group,SIGNAL(buttonClicked(int)),
            this,SLOT(btnsClickedSlot(int)));

    connect2DB();
}

void Dialog::btnsClickedSlot(int id)
{
    if(id == 1)
    {
        insertData();
    }else if(id == 2)
    {
        deleteData();
    }else if(id == 3)
    {
        updateData();
    }else if(id == 4)
    {
        selectLike();
    }
}

Dialog::~Dialog()
{
    //sqlite本质上是文件操作,Qt程序结束时任何打开的文件是会关掉的,但是最好要在程序中关闭连接。
    db.close();
    delete ui;
}

void Dialog::connect2DB()
{
    // 获得数据库连接对象
    db = QSqlDatabase::addDatabase("QSQLITE");
    // 数据库文件名称
    db.setDatabaseName("fruit_management.db");
    // 打开连接
    if(db.open())
    {
        qDebug() << "数据库连接成功!";
        createTable();
        selectAll();
    }else
    {
        // 获得错误信息
        QSqlError info = db.lastError();
        QString text = info.text();
        QMessageBox::critical(this,"错误",text.prepend("连接失败!"));
    }
}

void Dialog::createTable()
{
    // 建表语句
    QString sql = QString("CREATE TABLE fruit(\
                          id    INTEGER PRIMARY KEY,\
                          name  TEXT,\
                          loc   TEXT,\
                          price REAL);");
    sql = "CREATE TABLE fruit(id INTEGER PRIMARY KEY,name TEXT,loc TEXT,price REAL);";
    // 数据库操作类对象
    QSqlQuery sq;
    // 执行SQL语句
    if(sq.exec(sql))
    {
        qDebug() << "建表成功!";
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        qDebug() << text.prepend("建表失败!");
    }
}

void Dialog::insertData()
{
    // 如果名称不输入引导用户输入
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入名称!");
        return;
    }
    int id = ui->spinBox->value();
    QString loc = ui->comboBox->currentText();
    double price = ui->doubleSpinBox->value();
    // 预处理的SQL语句(ODBC风格)
    QString sql = "INSERT INTO fruit VALUES(?,?,?,?);";
    // 预处理SQL语句
    QSqlQuery sq;
    sq.prepare(sql);
    // 绑定参数(注意顺序)
    sq.addBindValue(id);
    sq.addBindValue(name);
    sq.addBindValue(loc);
    sq.addBindValue(price);
    // 正式执行SQL语句
    if(sq.exec()) // 如果预处理,则不能传递参数!!!
    {
        selectAll();
        QMessageBox::information(this,"通知","数据插入成功!");
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        QMessageBox::critical(this,"错误",text.prepend("插入失败!"));
    }
}

void Dialog::deleteData()
{
    int id = ui->spinBox->value();
    // 先看看要删除的数据在不在
    if(!isDataExists(id))
    {
        QMessageBox::information(this,"通知","您要删除的数据不存在");
        return;
    }
    // 预处理的SQL语句(ODBC风格)
    QString sql = "DELETE FROM fruit WHERE id=?";
    // 预处理SQL语句
    QSqlQuery sq;
    sq.prepare(sql);
    // 绑定参数(注意顺序)
    sq.addBindValue(id);
    // 正式执行SQL语句
    if(sq.exec()) // 如果预处理,则不能传递参数!!!
    {
        selectAll();
        QMessageBox::information(this,"通知","数据删除成功!");
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        QMessageBox::critical(this,"错误",text.prepend("删除失败!"));
    }
}

void Dialog::updateData()
{
    // 如果名称不输入引导用户输入
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入名称!");
        return;
    }
    int id = ui->spinBox->value();
    // 先看看要更新的数据在不在
    if(!isDataExists(id))
    {
        QMessageBox::information(this,"通知","您要更新的数据不存在");
        return;
    }
    QString loc = ui->comboBox->currentText();
    double price = ui->doubleSpinBox->value();
    // 预处理的SQL语句(Oracle风格)
    QString sql = "UPDATE fruit SET name=:name,loc=:loc,price=:price WHERE id=:id";
    // 预处理SQL语句
    QSqlQuery sq;
    sq.prepare(sql);
    // 绑定参数(注意顺序)
    sq.bindValue(":id",id);
    sq.bindValue(":name",name);
    sq.bindValue(":loc",loc);
    sq.bindValue(":price",price);
    // 正式执行SQL语句
    if(sq.exec()) // 如果预处理,则不能传递参数!!!
    {
        selectAll();
        QMessageBox::information(this,"通知","数据更新成功!");
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        QMessageBox::critical(this,"错误",text.prepend("更新失败!"));
    }
}

void Dialog::selectAll()
{
    QString sql = "SELECT * FROM fruit";
    // 数据库操作类对象
    QSqlQuery sq;
    // 执行SQL语句
    if(sq.exec(sql))
    {
        qDebug() << "查询成功!";
        // 清空显示
        ui->textBrowser->clear();
        // 循环取出每条记录的数据
        while(sq.next()) // 向后移动
        {
            // 获得各列数据
            QString id = sq.value(0).toString();
            QString name = sq.value("name").toString();
            QString loc = sq.value(2).toString();
            QString price = sq.value(3).toString();

            // 拼接
            QString text = id.append(" ")+name.append(" ")+
                    loc.append(" ") + price;

            // 拼接并显示
            ui->textBrowser->append(text);
        }
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        qDebug() << text.prepend("查询失败!");
    }
}

bool Dialog::isDataExists(int id)
{
    // 偶尔用一把字符串拼接
    QString sql = "SELECT * FROM fruit WHERE id=";
    sql.append(QString::number(id));
    // 数据库操作类对象
    QSqlQuery sq;
    // 执行SQL语句
    if(sq.exec(sql))
    {
        qDebug() << "查询成功!";
        return sq.next();
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        qDebug() << text.prepend("查询失败!");
        return false;
    }
}

void Dialog::selectLike()
{
    // 如果名称不输入引导用户输入
    QString name = ui->lineEdit->text();
    if(name == "")
    {
        QMessageBox::warning(this,"提示","请输入名称!");
        return;
    }
    // ODBC风格的预处理语句
    QString sql = "SELECT * FROM fruit WHERE name LIKE ?";
    // 预处理
    QSqlQuery sq;
    sq.prepare(sql);
    // 绑定参数
    sq.addBindValue(name.prepend("%").append("%")); // 模糊查询
    // 正式执行
    // 执行SQL语句
    if(sq.exec())
    {
        qDebug() << "查询成功!";
        // 清空显示
        ui->textBrowser->clear();
        // 循环取出每条记录的数据
        while(sq.next()) // 向后移动
        {
            // 获得各列数据
            QString id = sq.value(0).toString();
            QString name = sq.value("name").toString();
            QString loc = sq.value(2).toString();
            QString price = sq.value(3).toString();

            // 拼接
            QString text = id.append(" ")+name.append(" ")+
                    loc.append(" ") + price;

            // 拼接并显示
            ui->textBrowser->append(text);
        }
    }else
    {
        // 获得错误信息
        QString text = sq.lastError().text();
        qDebug() << text.prepend("查询失败!");
    }
}

dialog.ui

 

更多推荐