首页 Qt 学习之路 2 Qt 学习之路 2(55):数据库操作

Qt 学习之路 2(55):数据库操作

83 14

Qt 提供了 QtSql 模块来提供平台独立的基于 SQL 的数据库操作。这里我们所说的“平台独立”,既包括操作系统平台,又包括各个数据库平台。另外,我们强调了“基于 SQL”,因为 NoSQL 数据库至今没有一个通用查询方法,所以不可能提供一种通用的 NoSQL 数据库的操作。Qt 的数据库操作还可以很方便的与 model/view 架构进行整合。通常来说,我们对数据库的操作更多地在于对数据库表的操作,而这正是 model/view 架构的长项。

Qt 使用QSqlDatabase表示一个数据库连接。更底层上,Qt 使用驱动(drivers)来与不同的数据库 API 进行交互。Qt 桌面版本提供了如下几种驱动:

 驱动数据库
QDB2IBM DB2 (7.1 或更新版本)
QIBASEBorland InterBase
QMYSQLMySQL
QOCIOracle Call Interface Driver
QODBCOpen Database Connectivity (ODBC) - Microsoft SQL Server 及其它兼容 ODBC 的数据库
QPSQLPostgreSQL (7.3 或更新版本)
QSQLITE2SQLite 2
QSQLITESQLite 3
QSYMSQL针对 Symbian 平台的SQLite 3
QTDSSybase Adaptive Server (自 Qt 4.7 起废除)

不过,由于受到协议的限制,Qt 开源版本并没有提供上面所有驱动的二进制版本,而仅仅以源代码的形式提供。通常,Qt 只默认搭载 QSqlite 驱动(这个驱动实际还包括 Sqlite 数据库,也就是说,如果需要使用 Sqlite 的话,只需要该驱动即可)。我们可以选择把这些驱动作为 Qt 的一部分进行编译,也可以当作插件编译。

如果习惯于使用 SQL 语句,我们可以选择QSqlQuery类;如果只需要使用高层次的数据库接口(不关心 SQL 语法),我们可以选择QSqlTableModelQSqlRelationalTableModel。本章我们介绍QSqlQuery类,在后面的章节则介绍QSqlTableModelQSqlRelationalTableModel

在使用时,我们可以通过

QSqlDatabase::drivers();

找到系统中所有可用的数据库驱动的名字列表。我们只能使用出现在列表中的驱动。由于默认情况下,QtSql 是作为 Qt 的一个模块提供的。为了使用有关数据库的类,我们必须早 .pro 文件中添加这么一句:

QT += sql

这表示,我们的程序需要使用 Qt 的 core、gui 以及 sql 三个模块。注意,如果需要同时使用 Qt4 和 Qt5 编译程序,通常我们的 .pro 文件是这样的:

QT += core gui sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

这两句也很明确:Qt 需要加载 core、gui 和 sql 三个模块,如果主板本大于 4,则再添加 widgets 模块。

下面来看一个简单的函数:

bool connect(const QString &dbName)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//    db.setHostName("host");
//    db.setDatabaseName("dbname");
//    db.setUserName("username");
//    db.setPassword("password");
    db.setDatabaseName(dbName);
    if (!db.open()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              db.lastError().text());
        return false;
    }
    return true;
}

我们使用connect()函数创建一个数据库连接。我们使用QSqlDatabase::addDatabase()静态函数完成这一请求,也就是创建了一个QSqlDatabase实例。注意,数据库连接使用自己的名字进行区分,而不是数据库的名字。例如,我们可以使用下面的语句:

QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE", QString("con%1").arg(dbName));

此时,我们是使用addDatabase()函数的第二个参数来给这个数据库连接一个名字。在这个例子中,用于区分这个数据库连接的名字是QString("conn%1").arg(dbName),而不是 "QSQLITE"。这个参数是可选的,如果不指定,系统会给出一个默认的名字QSqlDatabase::defaultConnection,此时,Qt 会创建一个默认的连接。如果你给出的名字与已存在的名字相同,新的连接会替换掉已有的连接。通过这种设计,我们可以为一个数据库建立多个连接。

我们这里使用的是 sqlite 数据库,只需要指定数据库名字即可。如果是数据库服务器,比如 MySQL,我们还需要指定主机名、端口号、用户名和密码,这些语句使用注释进行了简单的说明。

接下来我们调用了QSqlDatabase::open()函数,打开这个数据库连接。通过检查open()函数的返回值,我们可以判断数据库是不是正确打开。

QtSql 模块中的类大多具有lastError()函数,用于检查最新出现的错误。如果你发现数据库操作有任何问题,应该使用这个函数进行错误的检查。这一点我们也在上面的代码中进行了体现。当然,这只是最简单的实现,一般来说,更好的设计是,不要在数据库操作中混杂界面代码(并且将这个connect()函数放在一个专门的数据库操作类中)。

接下来我们可以在main()函数中使用这个connect()函数:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (connect("demo.db")) {
        QSqlQuery query;
        if (!query.exec("CREATE TABLE student ("
                        "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                        "name VARCHAR,"
                        "age INT)")) {
            QMessageBox::critical(0, QObject::tr("Database Error"),
                                  query.lastError().text());
            return 1;
        }
    } else {
        return 1;
    }
    return a.exec();
}

main()函数中,我们调用这个connect()函数打开数据库。如果打开成功,我们通过一个QSqlQuery实例执行了 SQL 语句。同样,我们使用其lastError()函数检查了执行结果是否正确。

注意这里的QSqlQuery实例的创建。我们并没有指定是为哪一个数据库连接创建查询对象,此时,系统会使用默认的连接,也就是使用没有第二个参数的addDatabase()函数创建的那个连接(其实就是名字为QSqlDatabase::defaultConnection的默认连接)。如果没有这么一个连接,系统就会报错。也就是说,如果没有默认连接,我们在创建QSqlQuery对象时必须指明是哪一个QSqlDatabase对象,也就是addDatabase()的返回值。

我们还可以通过使用QSqlQuery::isActive()函数检查语句执行正确与否。如果QSqlQuery对象是活动的,该函数返回 true。所谓“活动”,就是指该对象成功执行了exec()函数,但是还没有完成。如果需要设置为不活动的,可以使用finish()或者clear()函数,或者直接释放掉这个QSqlQuery对象。这里需要注意的是,如果存在一个活动的 SELECT 语句,某些数据库系统不能成功完成connect()或者rollback()函数的调用。此时,我们必须首先将活动的 SELECT 语句设置成不活动的。

创建过数据库表 student 之后,我们开始插入数据,然后将其独取出来:

if (connect("demo.db")) {
    QSqlQuery query;
    query.prepare("INSERT INTO student (name, age) VALUES (?, ?)");
    QVariantList names;
    names << "Tom" << "Jack" << "Jane" << "Jerry";
    query.addBindValue(names);
    QVariantList ages;
    ages << 20 << 23 << 22 << 25;
    query.addBindValue(ages);
    if (!query.execBatch()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              query.lastError().text());
    }
    query.finish();
    query.exec("SELECT name, age FROM student");
    while (query.next()) {
        QString name = query.value(0).toString();
        int age = query.value(1).toInt();
        qDebug() << name << ": " << age;
    }
} else {
    return 1;
}

依旧连接到我们创建的 demo.db 数据库。我们需要插入多条数据,此时可以使用QSqlQuery::exec()函数一条一条插入数据,但是这里我们选择了另外一种方法:批量执行。首先,我们使用QSqlQuery::prepare()函数对这条 SQL 语句进行预处理,问号 ? 相当于占位符,预示着以后我们可以使用实际数据替换这些位置。简单说明一下,预处理是数据库提供的一种特性,它会将 SQL 语句进行编译,性能和安全性都要优于普通的 SQL 处理。在上面的代码中,我们使用一个字符串列表 names 替换掉第一个问号的位置,一个整型列表 ages 替换掉第二个问号的位置,利用QSqlQuery::addBindValue()我们将实际数据绑定到这个预处理的 SQL 语句上。需要注意的是,names 和 ages 这两个列表里面的数据需要一一对应。然后我们调用QSqlQuery::execBatch()批量执行 SQL,之后结束该对象。这样,插入操作便完成了。

另外说明一点,我们这里使用了 ODBC 风格的 ? 占位符,同样,我们也可以使用 Oracle 风格的占位符:

query.prepare("INSERT INTO student (name, age) VALUES (:name, :age)");

此时,我们就需要使用

query.bindValue(":name", names);
query.bindValue(":age", ages);

进行绑定。Oracle 风格的绑定最大的好处是,绑定的名字和值很清晰,与顺序无关。但是这里需要注意,bindValue()函数只能绑定一个位置。比如

query.prepare("INSERT INTO test (name1, name2) VALUES (:name, :name)");
// ...
query.bindValue(":name", name);

只能绑定第一个 :name 占位符,不能绑定到第二个。

接下来我们依旧使用同一个查询对象执行一个 SELECT 语句。如果存在查询结果,QSqlQuery::next()会返回 true,直到到达结果最末,返回 false,说明遍历结束。我们利用这一点,使用 while 循环即可遍历查询结果。使用QSqlQuery::value()函数即可按照 SELECT 语句的字段顺序获取到对应的数据库存储的数据。

对于数据库事务的操作,我们可以使用 QSqlDatabase::transaction() 开启事务,QSqlDatabase::commit() 或者QSqlDatabase::rollback() 结束事务。使用QSqlDatabase::database()函数则可以根据名字获取所需要的数据库连接。

83 评论

pkgfs 2013年6月15日 - 13:33

🙁 泪流满面,终于等到数据库这一天了,跪--

回复
豆子 2013年6月17日 - 09:05

不好意思哦~

回复
特地来支持豆子 2013年6月18日 - 23:32

😛 😛 支持

回复
dtfhhhh 2013年6月20日 - 21:17

哦,太好了,终于有数据库了。。。。特别是sqlite。。。

另外,请教一下,最近官方源里好像有qt5了,今天总算可以放心下载安装。不过,我找不到qt5的demo和doc啊?下载好的qt creator 里面没有这两个东西。doc只有简单介绍而己,请问我要安装哪个包才能给qtcreator捆绑起来?

回复
豆子 2013年6月21日 - 09:22

Qt5 的 demo 和 doc 在安装包里面就有的,不大清楚从安装源安装是什么名字。如果你直接下载安装包安装,QtCreator 和 Qt5 是设置好的,不需要额外的配置。

回复
dreamychi 2015年11月16日 - 11:39

Qt5应该是不带编译好的demo了,只带了demo源码,如果想看,只能在QtCreator的入口里或者是在demo源码的目录下,自己把源码编译一下运行起来看。这样倒是也挺好。用什么编什么

回复
j 2013年8月14日 - 11:07

如果没有这么一个连接,系统就会抱错

一个错别字。

回复
豆子 2013年8月15日 - 09:02

已经修改过了,感谢指出!

回复
morrin 2013年11月3日 - 10:01

请教豆子及各位高手一个问题:我编了下面这段打开数据库的程序,程序运行结果可以打开(open!),其中的"YY\SQLEXPRESS"和"master"是实际存在的hostname和dbname,但不知道为什么我任意乱写一个不存在的hostname或dbname,程序运行结果仍然是可以打开数据库?谢谢!

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("YY\SQLEXPRESS");
db.setDatabaseName("master");
if(db.open())
{
qDebug()<<"Open!";
db.close();
}
else
{
qDebug()<<"Error"<<db.lastError().text();
}

回复
豆子 2013年11月3日 - 22:06

你使用的是 SQLITE 数据库,这个数据库不存在主机和数据库名字的概念。所以设置 host 实际是没有效果的。看你的数据库主机名字像是 SQL Server,所以你应该加载 SQL Server 的驱动才可以。

回复
morrin 2013年11月5日 - 09:09

谢谢豆子指点,我的数据库确实是SQL Server,但是我把QSQLITE改为QODBC后,编译程序是会提示错误:qodbc driver not loaded。我用的是Qt5.0.1,我在网上查了很多,别人说Qt5中没有QODBC的驱动文件,我就按网上的办法,重新安装了Qt4.7.3,它里面就有QODBC的驱动文件,我就把这4个文件(两个.dll两个.a)拷贝到Qt5.0.1中的spldrivers文件夹中,可是编译后还是会提示错误:qodbc driver not loaded。

回复
豆子 2013年11月5日 - 09:29

Qt4 的代码与 Qt5 不是二进制兼容的,所以你不能直接把 Qt4 的驱动复制到 Qt5 中使用。如果你的 Qt5 没有附带 ODBC 的二进制版本(不过豆子在 Qt5.1.1 (OpenGL) 中的确发现了 qsqlodbc.dll,但是没有测试能不能加载成功,理论上应该没问题),你需要自己编译 ODBC 驱动。如果你安装了 Qt5 的源代码包,你会在 Src/qtbase/src/sql/drivers 里面找到 QODBC 的源代码,然后尝试编译 QODBC(你可以在文档中找到编译方法;或者这里)。需要注意的是,你编译 QODBC 使用的编译器必须同 Qt 的编译版本一致。比如你安装的是 VS2010 版本的 Qt5,那么你必须使用 VS2010 的编译器进行编译,然后把编译好的 dll 复制到 sqldrivers 文件夹下就可以了。

回复
morrin 2013年11月5日 - 13:33

已按照你的提示解决了问题,十分感谢!真搞不懂为什么qt5.0.1中没有qsqlodbc.dll?

豆子 2013年11月5日 - 19:27

这个不大清楚,没准儿是忘记了,还是由于协议的问题?

liyingju 2014年4月23日 - 10:08

那我用的是Qt5.2.1 mingw 咋解决啊

豆子 2014年4月25日 - 09:15

那就用 mingw 编译呗

morrin 2013年12月3日 - 18:26

豆子你好,请教一个问题,是关于botan的,我用Qt5.0.1(Qtcreator2.6.2, mingw47)打开qt-creator-2.0.1-src中的botan.pro,然后build,但是为什么只生成Botand.dll和ilbBotand.a两个文件?正确的是应该生成四个文件:Botan.dll 、libBotan.a 、Botand.dll、libBotand.a四个文件。谢谢!

回复
豆子 2013年12月3日 - 21:26

带有 d 的是 debug 版本,大概因为你的 pro 文件中没有添加 DEBUG 之类的宏。至于这个宏这么写,就要去看看文档了。没有 debug 版本其实也没有关系,只是不能调试。

回复
morrin 2013年12月3日 - 22:17

我把botan.pro文件中的TEMPLATE = subdirs改为TEMPLATE = lib后,生成了其余的两个文件:Botan.dll 、libBotan.a .但和之前的那两个文件不在同一文件夹。

回复
ljt 2014年5月14日 - 21:23

我用insert语句向数据库中插入一条记录,记录中有一个是自增的字段id,在sql server中可用通过下面语句获得自增的id。
如:INSERT INTO jobs (job_desc,min_lvl,max_lvl) VALUES ('Accountant',12,125) SELECT @@IDENTITY AS 'Identity'
但是:QSqlQuery query;
QString strSql = 上面语句;
query.exec(strSql);//返回true
if(query.next())//j返回false
{
}
直接query.value(0)也得不到值;
请问如果获得自增的id

回复
豆子 2014年5月16日 - 08:57

直接使用 QSqlQuery::lastInsertId() 函数获取试试看。

回复
ljt 2014年5月23日 - 08:27

谢谢,sqlserver不行,我最后用存储过程实现了。

回复
yh 2019年7月9日 - 17:58

您好,请问有时间的话能不能把这个插件静态编译一下,不知道为什么 我这边直接使用静态编译的Qt编译出来的静态库无法使用,就算把libsqlitecipher.a和libsqlitecipherd.a文件放入plugins\sqldrivers下面,运行后依然没有这个插件的驱动!

回复
刘小宇 2014年6月5日 - 14:55

一直报这个table ..... already exists Unable to execute statement怎么解决??

回复
刘小宇 2014年6月5日 - 15:28

小白了,懂了。。

回复
风出闹闹 2016年2月8日 - 21:14

怎么弄啊不懂

回复
155cannon 2016年3月14日 - 13:25

同遇到这个问题,想不明白,懂的人说说,谢谢!

回复
155cannon 2016年3月14日 - 13:33

也是懂了

回复
大川 2014年8月19日 - 18:06

您好,请问QVariantList 是不是可以用QLIst代替啊

回复
豆子 2014年8月20日 - 21:09

QVariantList就是typedef QList<QVariant>

回复
fanxiao 2014年9月25日 - 17:31

QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
说myql 驱动没有加载,但是在E:\Qt\Qt5.3.1\5.3\mingw482_32\plugins\sqldrivers 存在qsqlmysql.dll 文件 我copy到 qt creator 目录下 还是说mysql 驱动没有加载 什么意思啊?
但是 打印 支持mysql 驱动啊

回复
豆子 2014年9月25日 - 17:44

会不会是版本问题?你说的“打印支持”,是输出的已经加载的驱动列表吗?

回复
fanxiao 2014年9月26日 - 13:48

是的 available Device 里面有QMYSQL
但是我用的都是QT5.3.1的版本 不过安装了个QT5.2的版本

回复
豆子 2014年9月28日 - 09:00

会不会是版本的问题?你是说插件和 Qt 版本不一致?这个具体我没有试过,方便的话可以发一个测试程序到 devbean#outlook.com

回复
BeanKo 2015年3月29日 - 09:53

哈哈,从你的豆子空间学到这里来了。
请教下豆子:
我QT4.8.6+VS2010。
我想编译QMYSQL的,可官方教程里在QT的plugins里有mysql及mysql.pro,可我的文件里却没有。
请教下我该如何去编译QMYSQL?

回复
豆子 2015年3月31日 - 10:31

如果没有的话,可以到 git 仓库将 QMYSQL 源代码 clone 下来进行编译。有可能在安装 Qt 的时候没有选择安装 source。

回复
epr 2015年4月17日 - 11:29

博主,您好:
请问一下,使用qt5.4在vs2010下,怎么给数据库添加中文字符啊?

回复
豆子 2015年4月21日 - 12:26

不知道是什么数据库啊?中文字符一般是可以直接添加的,需要注意的是编码要一致。

回复
wangdapao 2015年5月8日 - 23:04

QSqlDatabase: QMYSQL driver not loaded
QSqlDatabase: available drivers: QSQLITE QMYSQL QMYSQL3 QODBC QODBC3 QPSQL QPSQL7
豆子老师 这是什么意思

回复
豆子 2015年6月3日 - 11:16

没有加载 MySQL 驱动,一般是没有找到。

回复
dedje 2015年6月7日 - 21:57

HEAP[mainwin.exe]: Invalid address specified to RtlValidateHeap( 005F0000, 00658F60 )
老师,你好,一直报这个错误怎么办?

回复
豆子 2015年6月11日 - 09:30

这种错误一般是因为内存问题,检查下是不是哪里有对象未创建之类

回复
杨华波 2015年7月8日 - 15:21

你好,我在使用exec()函数的时候,如果网络断开,或者数据库所在的服务器资源紧张如cpu占用比较高的时候,exec()会卡主,很长时间都不返回。可否通过设置参数来解决这个问题,谢谢~~

回复
豆子 2015年7月13日 - 11:02

早期版本没有超时的设置(最新版 5.5 没有研究),一般使用一个 QTimer 定时器做超时。

回复
杨华波 2015年7月28日 - 17:39

怎么做啊,纠结了好久都没整出来,您有这方面的例子么,给一个喽。

回复
小E先森 2015年8月6日 - 17:26

楼主你好,我用qt连接远程的mysql,提示连接成功,但是执行query.exec("select * from production"); 结果是false,即查询不到数据,但我的production表是有数据的,我用同样代码读取本地的production表,结果能读取。。。这是什么问题

回复
豆子 2015年8月16日 - 17:09

可以用 lastError() 看看有什么错误

回复
llwj0303 2015年9月6日 - 10:36

楼主你好,问下QSqlite怎么存储QPath,QPoint,Qlist及自定义的一些类型,如果不行,用其他数据库能做到么

回复
豆子 2015年9月7日 - 10:30

数据库中存储的应该是值,而不是类型。比如 QPoint,在数据库中应该存入 x 和 y 的具体值,读取之后重新新建一个 QPoint 对象,然后赋值。直接存储对象也是可以的,需要首先将对象序列化,读取时要反序列化。不过,这样的话,数据库中的数据就是特定平台的了,对人读也不友好。

回复
Edwardweiwei 2016年3月17日 - 14:51

请问豆子,我用你的代码后编译时出现错误 Driver not Loaded Driver not Loaded的Database Error错误,百度各种找不到解决办法,用的是qt-opensource-windows-x86-android-5.5.1,在另一台电脑上安装后还是一样的错误,毫无办法啊!

回复
豆子 2016年3月18日 - 15:53

这个应该是数据库驱动没有找到,看看是不是写错了驱动名字还是什么原因?

回复
Edwardweiwei 2016年3月18日 - 16:10

你好豆子,这个问题解决了,是把 QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE", QString("con%1").arg(dbName));
用前面那个 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(dbName); 这样分开写后就好了,也不知道为什么用第一个方法写就会出现那种奇怪错误。

回复
manmanman 2016年3月21日 - 17:04

请问大神 程序运行时数据库载入失败要怎么解决啊

回复
manmanman 2016年3月22日 - 15:12

qt错误0*00000a38指令引用的内存,不能为read,不知道要怎么解决,求大神指导

回复
manmanman 2016年3月22日 - 16:35

void loginDialog::on_loginBtn_clicked()
{
model = new QSqlTableModel(this);
model->setTable("user");
model->select();
int i;
for(i=0;irowCount();i++)
{
QSqlRecord record=model->record(i);
if(record.value(1)==ui->userLineEdit->text()&&
record.value(2)==ui->pwdLineEdit->text())
{
QString str1="登录成功";
QString str2=record.value(1).toString();
QMessageBox::information(this,"提示",str2+str1,QMessageBox::Yes);
accept();
}
else if(record.value(1)==ui->userLineEdit->text()&&
record.value(2)!=ui->pwdLineEdit->text())
{
QMessageBox::information(this,"提示","密码输入有误",QMessageBox::Yes);
ui->userLineEdit->clear();
ui->pwdLineEdit->clear();
ui->userLineEdit->setFocus();
return;
}

QMessageBox::warning(this,"提示","用户不存在,请注册",QMessageBox::Yes);
ui->userLineEdit->clear();
ui->pwdLineEdit->clear();
ui->userLineEdit->setFocus();
return;
}
}
请问应该怎样改,输入用户名和密码显示用户名不存在

回复
Devil 2016年5月4日 - 22:46

请问下,QT下怎么使用exec()的回调形式啊

回复
Kian 2016年5月23日 - 08:08

长时间不访问数据库会自动断开连接。在终端里面执行语句会自动重新连接,不需要输入密码之类的;但是在QT里面不行,请问QSqlDatabase有相关属性设置吗?
还是只能在每次执行语句前都去查询数据库连接状况,如果没有连接调用一次连接函数?或者用一个定时器定时去执行保持数据库连接?

回复
豆子 2016年5月23日 - 21:17

数据库重连一般是需要在连接时单独设置。QSqlDatabase
提供了setConnectOptions()函数,用于设置连接参数。可以依据使用的数据库提供具体的参数,例如,MySQL 提供了MYSQL_OPT_RECONNECT=1这样的参数,用于重连。具体需要查阅数据库的相关文档。另外,如果不起作用,可以考虑用SELECT 1这样的语句进行测试,如果查询失败,认为已经断开,那么就先close()open()来试一下

回复
southpolaris 2016年6月22日 - 18:20

豆子老师请问下,我在ubuntu16.04 和 qt5.6 64位环境下遇到一个问题,在示例中的出现查看错误的lasterror函数编译clang给出下面的错误。注释lasterror这个函数可以编译成功。
calling 'last Error' with incomplete return type 'QSqlError'

bool Database::connectDB(const QString &dbName)
{
m_database = QSqlDatabase::addDatabase("QSQLITE");
m_database.setDatabaseName(dbName);

if (!m_database.open())
{
qDebug() << "Database: connect failed" << m_database.lastError().Text(); //这里编译出错
return false;
}
return true;
}

回复
豆子 2016年6月23日 - 16:55

可能是你没有 include QSqlError

回复
虫子 2016年7月7日 - 16:40

豆子,你好!我想请教你一个问题,我使用sql模型数据来连接数据库操作,在提交时数据有生僻字,提交后显示的是个问号"?",我使用的字符集是gbk,能帮忙分析下吗?

回复
豆子 2016年7月8日 - 14:25

是不是 gbk 编码问题,sqlite 默认使用 utf-8 编码,你换成 utf-8 试试看看怎么样呢?

回复
x_hong 2016年7月22日 - 10:30

豆子老师你好,我按教程写的数据库连接,生成了可执行文件,可执行文件在装了Qt的电脑上可连接数据库,换台没装Qt的电脑就显示数据库打开失败,应该是在db.open那一句那儿,相关的dll我是都拷贝过去了的?请问怎么回事呢?

回复
x_hong 2016年7月22日 - 10:36

相关的数据库包括libgcc_s_dw2-1.dll mingwm10.dll qsqlite4.dll qsqlodbc4.dll Qtcore4.dll QtGui4.dll QtOpenGL4.dll QtSql4.dll QtSvg4.dll QtTest4.dll qwt.dll 另有一个数据库文件与可执行文件在同一文件夹下。我在debug和release版本下都遇到了这个问题,没有百度到可用的方案。

回复
豆子 2016年7月23日 - 10:58

默认情况下,qsqlite4.dll、qsqlodbc4.dll 应该是在 sqldrivers 文件夹下,并不是与 exe 同目录下的。这些属于 Qt 插件,有自己的插件目录结构,应该按照 Qt 的目录结构放置

回复
ben 2016年9月21日 - 16:50

发现一个文字错误:
这里我们所说的“平台独立”,既包括操作系统平台,有(又?)包括各个数据库平台...

回复
豆子 2016年9月21日 - 21:26

感谢指出!

回复
ben 2016年9月26日 - 11:02

有个疑问:connect()函数创建一个数据库连接QSqlDatabase db,那么在函数作用域之外db不是自动失效了吗?为什么下面的QSqlQuery query还能用到这个连接呢?

回复
豆子 2016年10月16日 - 22:13

QSqlDatabase 是类似单例的形式,相当于一种注册的操作,所以是可以使用的

回复
ben 2016年10月4日 - 18:03

博主,请教一个问题:1个qsqlquery怎么与qsqldatabase关联起来?

这个问题的起因是连接mysql数据库时出现错误:连接数据库已经正常了,但是query执行sql语句后提示“driver not loaded”的错误,后来查了一下有个博客说:
----------------
说明你的query在创建的时候没有和qsqldatabase建立起关联.正确的方法是声明qsqldatabase后就声明query.如果你希望一 个连接能够和多个query关联使用如下语法:QSqlQuery query(db),db是QSqlDatabase的实例名.
----------------
两种办法我都试了,都不行:
1. 在自己定义的MySql中声明成员变量QSqlDatabase db_,然后再声明QSqlQuery query_
2.在自己定义的MySql中声明成员变量QSqlDatabase db_,然后再声明QSqlQuery query(QSqlDatabase db_)

如果QSqlDatabase和QSqlQuery变量都已经声明,那后面有什么办法把这两者关联起来吗?

回复
ben 2016年10月6日 - 11:53

找到原因了:query必须在db已经连接之后关联才有用。
QSqlQuery query_temp(db_);
query_ = query_temp;

回复
ccppaa 2016年11月2日 - 16:52

大神,我用的是qt5.5连的本地数据库是SQLITE,之前一直没问题,今天突然莫名其妙有一个insert语句不好用,调试出给的错误是QSqlError("", "", ""),看了毫无方向,求帮忙啊,程序里有很多insert语句,只有这一句不好用

回复
豆子 2016年11月19日 - 10:40

这个不知道怎么回事,可能是哪里有了错误,需要看代码才会知道

回复
Yan 2017年3月15日 - 04:18

QSqlDatabase myDB = QSqlDatabase::addDatabase("QODBC");
QString QtDBTest = QString (伺服器设定就不看了);

myDB.setDatabaseName(QtDBTest);
myDB.open();
QSqlQueryModel *model = new QSqlQueryModel();
model->setQuery("SELECT * FROM Robot_Condition");
model->query().exec();
model->setHeaderData(0, Qt::Horizontal, "ID");
model->setHeaderData(1, Qt::Horizontal, "X_axis");
model->setHeaderData(2, Qt::Horizontal, "Y_axis");
model->setHeaderData(3, Qt::Horizontal, "angle");
model->setHeaderData(4, Qt::Horizontal, "battery");
QTableView *view = new QTableView;
view->setWindowTitle("QSqlQueryModel");
view->setModel(model);
view->show();
myDB.close();

然而显示的表是空白的 , 把myDB.close();删除就可以显示出表的数据
但却会卡顿 表的资料量也不大 请问该怎么解决?

回复
Yan 2017年3月15日 - 04:30

model->query().exec(); 这句是没有的 没改好

回复
ben 2017年5月11日 - 22:17

QSqlDatabase::addDatabase("QSQLITE"); // addDatabase()到底是创建一个数据库连接,还是创建一个数据库?

按照我的理解,创建一个数据库连接是数据库文件已经存在,创建一个连接与这个数据库文件连上;创建一个数据库则是数据库不存在,要创建一个数据库文件。

例中的代码执行后会生成一个数据库文件,那这就不是创建数据库连接,而是创建数据库了啊。

回复
豆子 2017年5月13日 - 16:57

对于 sqlite 是这样的,如果数据库文件存在就直接连接,不存在则创建。如果是其它类型数据库,比如 mysql 之类,不存在就会直接报错的

回复
ben 2017年5月14日 - 20:18

谢谢回复,我用1个有数据的数据库文件试了下,确实是这样的,之前还担心如果数据库已经存在的话会被覆盖。

回复
ben 2017年5月11日 - 22:26

main() 那段代码有个问题:运行后.exe会一直显示在任务管理器中,不会自动关闭,这是什么情况?

回复
豆子 2017年5月13日 - 17:01

因为我们在 main() 函数中开启了事件循环(通过调用 exec()),数据库连接之后没有其它操作,事件循环不会自动退出,所以会一直执行。这一段代码实际并不需要事件循环,所以你将 return a.exec(); 改成 return 0; 就可以了

回复
小白峻 2019年5月17日 - 14:39

豆子,我发现id自增那里,我用不了AUTOINCREMENT,只能用Identity,这是为什么?

回复
豆子 2019年5月21日 - 13:30

Identity 和 AUTOINCREMENT 都是数据库的语法。一般 SQL Server 支持 Identity,MySQL 支持 AUTOINCREMENT。可能是你使用的数据库不同的关系。

回复
小学生Kane 2020年9月1日 - 13:22

两次if (connect("demo.db")),第一次叫connect返回后,创建的数据库不会在栈上释放掉么。如果没的话,第二次叫不会覆盖嘛

回复

发表评论

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2