我的QT Creator学习笔记(三十三)——Qt中连接与使用数据库

Qt中的Qt SQL模块提供了对数据库的支持,要使用该模块时需要在项目文件(.pro文件)中添加“QT += sql"

该模块中的众多类基本上可以分为三层,如下表所示

对应的类
用户接口层

QSqlQueryModel, QSqlTableModel, QSqlRelationalTableModel

SQL接口层

QSqlDatabaseQSqlQuery,QSqlError, QSqlField, QSqlIndex, QSqlRecord

驱动层

QSqlDriver, QSqlDriverCreator, QSqlDriverCreatorBase, QSqlDriverPluginQSqlResult

 

 

 

 

 

驱动层为具体数据库和SQL接口层之间提供了底层桥梁;SQL接口层中QSqlDatabase用来创建连接QSqlQuery使用sql语句来实现与数据库的交互;用户接口层的几个类实现了将数据库中的数据连接到窗口部件上。

一、连接数据库

 1.1 SQL数据库驱动

使用QSqlDatabase的静态函数drivers()可以获取可用的数据库驱动列表,比如下面代码,打印出了我所使用的QT可用的数据库驱动
 QStringList drivers=QSqlDatabase::drivers();
 foreach(QString driver,drivers)
     qDebug()<<driver;

结果如下(不同版本QT可能会不一样)

"QSQLITE"

"QMYSQL"

"QMYSQL3"

"QODBC"

"QODBC3"

"QPSQL"

"QPSQL7"

1.2创建数据库连接

创建一个连接会创建一个QSqlDatabase类的实例饿,只有调用open()函数后该连接才可以被使用。下面代码段显示了创建一个默认连接,然后初始化一些连接信息,最后打开它。若打开成功就可以使用该连接了。

 QSqlDatabase db=QSqlDatabase::addDatabase("QMYSQL");
 db.setDatabaseHostName("bigblue");
 db.setDatabaseName("mydb");
 db.setUserName("user1");
 db.setPassword("123456");
 bool ok=db.open();

注意!setDatabaseName是指定连接到哪个数据库,如果数据库已经存在,则直接连接到这个数据库,如果不存在会创建该名称数据库。

addDatabase函数原型如下,第一个参数为驱动,第二参数为连接名。

 

static QSqlDatabase addDatabase(QSqlDriver* driver,
                                 const QString& connectionName =          QLatin1String(defaultConnection));

指定连接名的代码


 QSqlDatabase firstDb=QSqlDatabase::addDatabase("QMYSQL","First");
 QSqlDatabase secondDb=QSqlDatabase::addDatabase("QMYSQL","Second");

创建完连接后可以使用QSqlDatabase::databse()函数通过连接名获得连接。

 QSqlDatabase defaultDb=QSqlDatabase::database();//返回默认连接
 QSqlDatabase firstDb=QSqlDatabase::database("First");//返回"first"连接
 QSqlDatabase secondDb=QSqlDatabase::database("Second");//返回"second"连接

1.3 移除数据库连接

要移除数据库需要使用close和removeDatabase函数,示例代码如下。

 QSqlDatabase firstDb=QSqlDatabase::addDatabase("QMYSQL","First");
 //使用firstdb
 //......
 firstDb.close();//关闭数据库
 QSqlDatabase::removeDatabase("first");//移除数据库

二、 执行SQL语句

2.1 执行sql语句

要执行SQL语句只需要创建一个QSqlQuery对象,然后调用exec函数即可。代码如下

 //QSqlQuery query(db);
 QSqlQuery query;
 query.exec("select * from student");

QSqlQuey的构造函数可以接收一个可选的QSqlDatavase对象,来指定使用的是哪一个数据库连接,如上图中注释掉的代码。

2.2 浏览结果集

执行完查询语句后,QSqlQUey的内部指针会第一条记录前面的位置,可以使用next()函数来使其前进到第一条记录,继续使用next遍历后面的记录,示例代码如下

    QSqlQuery query;
    query.exec("select * from student");
    while(query.next())
    {
        qDebug()<<query.value(0).toInt()<<","<<query.value(1).toString();
    }

除了next函数,另外还有几个定位函数:previous()定位到前一条记录;first()定位到第一条记录;last()定位到最后一条记录;seek(n)定位到第n条记录。at()函数可以返回当前行的索引;record函数返回当前记录。

2.3 插入、插入更新和删除记录

query.exec("insert into student (id,name) values(0,'LiMing')");

插入操作除了直接执行如上所示插入语句外,更常用的是使用占位符来完成,Qt支持两种占位符:名称绑定和位置绑定

名称绑定:

query.prepare("insert into student (id,name) values(:id,:name)");
int idValue=0;
QString nameValue="LiMing";
query.bindValue(":id",idValue);
query.bindValue(":name",nameValue);
query.exec()

位置绑定:

query.prepare("insert into student (id,name) values(?,?)");
int idValue=0;
QString nameValue="LiMing";
query.addValue(idValue);
query.addValue(nameValue);
query.exec()

更新和删除与插入类似。

2.4 事务

事务可以保证一个复杂操作的原子性。可以使用QSqlDatabase::transaction()来启动一个事务,然后编写一些希望在事务中执行的语句,最后调用QSqlDatabase::commit()提交事务或者QSqlDatabase::rollback()回滚事务,示例代码

    QSqlDatabase::database().transaction();
    QSqlQuery query1;
    query1.exec("select id from employee where name='Tom'");
    if(query.next())
    {
        int employeeId=query1.value(0).toInt();
        query1.exec("insert into project(id,name,ownerid) values (201,'Manhattan Project',"+QString::number(employeeId)+')');
    }
    QSqlDatabase::database().commit();
    return a.exec();

 

三、代码例子

下面例子演示了上述中的1、根据连接名创建两个不同的连接,指向不同数据库。2、执行sql语句,创建表格,插入数据。3、浏览数据。4、移除数据库连接

#include <QApplication>
#include <QSqlDatabase>
#include <QDebug>
#include <QStringList>
#include <QVariant>
#include <QMessageBox>
#include <QSqlQuery>

static bool createConnection();

int main(int argc,char* argv[])
{
    QApplication a(argc,argv);
    //创建数据库连接
    if(!createConnection())
        return -1;
    //使用QSqlQuery查询连接1的整张表
    //如果不把操作这一部分括起来,会因为引用计数问题,最后removeDatabase时有警告
   {
        QSqlDatabase db1=QSqlDatabase::database("connection1");
        QSqlQuery query1(db1);
        qDebug()<<"Connection1:";
        query1.exec("select * from student");
        while(query1.next())
        {
            qDebug()<<query1.value(0).toInt()<<","<<query1.value(1).toString();
        }

        //使用QSqlQuery查询连接1的整张表
        QSqlDatabase db2=QSqlDatabase::database("connection2");
        QSqlQuery query2(db2);
        qDebug()<<"Connection2:";
        query2.exec("select * from student");
        while(query2.next())
        {
            qDebug()<<query2.value(0).toInt()<<","<<query2.value(1).toString();
        }
        //connection1和connection2的第一条记录
        qDebug()<<"Connection1 last record:";
        query1.last();
        qDebug()<<query1.value(0).toInt()<<","<<query1.value(1).toString();
        qDebug()<<"Connection2 last record:";
        query2.last();
        qDebug()<<query2.value(0).toInt()<<","<<query2.value(1).toString();

        //移除数据库连接
        db1.close();
        db2.close();
    }
    QSqlDatabase::removeDatabase("connection1");
    QSqlDatabase::removeDatabase("connection2");
    return a.exec();
}

static bool createConnection()
{
    //创建一个数据库连接,使用"connection1"为连接名
    QSqlDatabase db1=QSqlDatabase::addDatabase("QSQLITE","connection1");
    db1.setDatabaseName("my3.db");
    if(!db1.open())//如果打开失败,弹出提示
    {
        QMessageBox::critical(0,"Cnanot open database1","Unable to establish a database connection.",QMessageBox::Cancel);
        return false;
    }

    //指定连接
    QSqlQuery query1(db1);
    query1.exec("create table student (id int primary key,name varchar(20))");
    query1.exec("insert into student values(0,'LiMing')");
    //使用位置绑定插入
    query1.prepare("insert into student(id,name) values(?,?)");
    query1.addBindValue(1);
    query1.addBindValue("LiuTao");
    query1.exec();

    //使用名称绑定插入
    query1.prepare("insert into student(id,name)values(:id,:name)");
    query1.bindValue(":id",2);
    query1.bindValue(":name","ChenHong");
    query1.exec();

    //创建另一个数据库连接,使用不同的连接名,"connection2"
    QSqlDatabase db2=QSqlDatabase::addDatabase("QSQLITE","connection2");
    db2.setDatabaseName("my2.db");
    if(!db2.open())//如果打开失败,弹出提示
    {
        QMessageBox::critical(0,"Cnanot open database2","Unable to establish a database connection.",QMessageBox::Cancel);
        return false;
    }
    //指定连接
    QSqlQuery query2(db2);
    //创建表格插入数据
    query2.exec("create table student (id int primary key,name varchar(20))");
    query2.exec("insert into student values(10,'Tom')");
    query2.exec("insert into student values(11,'Lucy')");
    query2.exec("insert into student values(12,'Lily')");

    return true;

}

运行效果

我的QT Creator学习笔记(三十三)——Qt中连接与使用数据库

如果出现警告:QSqlDatabasePrivate::removeDatabase: connection 'myConnectionName' is still in use, all queries will cease to work

解决方法参考:https://*.com/questions/48827940/qsqldatabaseprivateremovedatabase-connection-myconnectionname-is-still-in-u

 

 

 

 

 

上一篇:Cocos Creator 源码解读:引擎启动与主循环


下一篇:我的QT Creator学习笔记(三十二)——模型/视图编程之委托类