QSqlQuery query("SELECT * FROM user");
QSqlRecord record = query.record();
while (query.next())
for (int i = 0;i<record.count();i++)
QString name = query.value(i).toString();
qDebug()<<name<<"\t";
qDebug()<<"\n";
执行结果:
int QSqlQuery::numRowsAffected() const
size()用来获取SELECT语句查询到的记录条数。如果大小无法确定或数据库不支持报告有关查询大小的信息,则返回-1。 注意,对于非select语句(isSelect()返回false), size()将返回-1。 如果查询不是活动的(isActive()返回false),则返回-1。
numRowsAffected()返回受结果的SQL语句影响的行数,如果不能确定,则返回-1。 注意,对于SELECT语句,该值是未定义的; 使用size()。 如果查询未激活,则返回-1。
Oracle数据库使用冒号-名称
语法来标识占位符,例如:name。 ODBC简单使用 ? 字符。 Qt支持这两种语法,但有一个限制,就是不能在同一个查询中混合使用它们。
可以使用boundValues()检索单个变量(映射)中所有字段的值。
QSqlQuery支持预先准备的查询执行和将参数值绑定到占位符。 有些数据库不支持这些特性,所以对于这些特性,Qt会模拟所需的功能。
Oracle数据库使用冒号语法识别占位符,例如:name。 ODBC仅仅使用? 字符。 Qt支持这两种语法,只是不能将它们混合在同一个查询中。
QSqlQuery 支持将参数值绑定到占位符。
下面展示了使用几种不同绑定方法将值绑定到存储过程的示例。
使用命名占位符的命名绑定:
QSqlQuery query;
query.prepare("INSERT INTO user (id, username, nickname)"
"VALUES (:id, :username, :nickname)");
query.bindValue(":id",520);
query.bindValue(":username","maye");
query.bindValue(":nickname","顽石");
query.exec();
使用命名占位符的位置绑定:
QSqlQuery query;
query.prepare("INSERT INTO user (id, username, nickname)"
"VALUES (:id, :username, :nickname)");
query.bindValue(0,520);
query.bindValue(1,"maye");
query.bindValue(2,"顽石");
query.exec();
使用位置占位符绑定值(版本1):
QSqlQuery query;
query.prepare("INSERT INTO user (id, username, nickname)"
"VALUES (?,?,?)");
query.bindValue(0,520);
query.bindValue(1,"maye");
query.bindValue(2,"顽石");
query.exec();
使用位置占位符绑定值(版本2):
QSqlQuery query;
query.prepare("INSERT INTO user (id, username, nickname)"
"VALUES (?,?,?)");
query.addBindValue(520);
query.addBindValue("maye");
query.addBindValue("顽石");
query.exec();
另外,未绑定的参数将导致操作失败。
方式一:addBindValue()
在query.prepare()中输入自己想要执行的语句,其中待输入的值用“?”代替,在这里“?”就是通配符。后面再用idList、nameList、ageList和mathList添加自己想要设置的值。注意,addBindValue()绑定值的顺序需要与id、name、age、math的顺序一致。在批处理中执行先前准备的SQL查询。 所有绑定参数都必须是变量列表。
QSqlQuery query;
query.prepare("insert into student (id,name,age,math) values (?,?,?,?)"); //书写语句模型
//添加绑定数据
QVariantList idList;
idList << 15<<16<<17; //创建一个id列表
query.addBindValue(idList); //完成第一个?的绑定
QVariantList nameList;
nameList << "ddd"<<"eee"<<"jjj";//创建一个name列表
query.addBindValue(nameList); //完成第二个?的绑定
QVariantList ageList;
ageList << 25<<24<<23; //创建一个age列表
query.addBindValue(ageList); //完成第三个?的绑定
QVariantList mathList;
mathList << 90<<89<<90; //创建一个math列表
query.addBindValue(mathList); //完成第四个?的绑定
query.execBatch();//执行批处理
方式二:bindValue()
直接用自定义的名称来完成绑定,这时绑定顺序可以自己决定。
QSqlQuery query;
query.prepare("insert into student (id,name,age,math) values (:id,:name,:age,:math)"); //:id之类的名字时自定义的 自己方便就好
//添加绑定数据
QVariantList idList;
idList << 18<<19<<20;
query.bindValue(":id",idList); //完成:id的绑定
QVariantList nameList;
nameList << "ddd"<<"eee"<<"jjj";
query.bindValue(":name",nameList); //完成:name的绑定
QVariantList ageList;
ageList << 25<<24<<23;
query.bindValue(":age",ageList); //完成:age的绑定
QVariantList mathList;
mathList << 90<<89<<90;
query.bindValue(":math",mathList); //完成:math的绑定
query.execBatch();//执行批处理
注意:每个绑定的QVariantList必须包含相同数量的变量。
注意:列表中qvariables的类型不能更改。 例如,您不能在QVariantList中混合整数和字符串变量。
2.3 QSqlRecord
QSqlRecord类封装了数据库记录(通常是数据库中的表或视图中的一行)的功能和特征。 QSqlRecord支持添加和删除字段,以及设置和检索字段值。
使用setValue()可以通过名称或位置设置记录字段的值; 如果你想设置一个字段值为空,使用setNull()。 要按名称查找字段的位置,请使用indexOf(),要在特定位置查找字段的名称,请使用fieldName()。 使用field()检索给定字段的QSqlField对象。 使用contains()查看记录是否包含特定的字段名。
当生成要在数据库上执行的查询时,生成的SQL中只包含isGenerated()为true的字段。
一条记录可以有通过append()或insert()添加的字段,通过replace()替换的字段,以及通过remove()删除的字段。 可以使用clear()删除所有字段。 字段的数量由count()给出; 所有它们的值都可以使用clearValues()清除(为空)。
对SqlRecord记录字段操作不会影响到原来的表。
QSqlQuery query("select * from user");
QSqlRecord rec = query.record();
qDebug() << "列数: " << rec.count();
int nameCol = rec.indexOf("name"); // 字段“name”的索引
while (query.next())
qDebug() << query.value(nameCol).toString(); // 输出所有name
执行结果:
2.4 QSqlField
QSqlField表示数据库表或视图中单个列的特征,例如数据类型和列名。 字段还包含数据库列的值,可以查看或更改该值。
字段数据值存储为qvariant。 不允许使用不兼容的类型。 例如:
QSqlField field("age", QVariant::Int);
field.setValue(QPixmap()); // WRONG
但是,在可能的情况下,字段会尝试将某些数据类型转换为字段数据类型:
QSqlField field("age", QVariant::Int);
field.setValue(QString("123")); // casts QString to int
很少在应用程序代码中显式创建QSqlField对象。 它们通常通过已经包含字段列表的QSqlRecords间接访问。 例如:
QSqlQuery query;
QSqlRecord record = query.record();
QSqlField field = record.field("country");
QSqlField对象可以提供一些关于字段的元数据,例如,它的name()、variant type()、length()、precision()、defaultValue()、typeID()以及它的requiredStatus()、isGenerated()和isReadOnly()。 可以检查字段的数据,看看它是否为null(),并检索它的值()。 当编辑数据时,可以使用setValue()设置或使用clear()设置为NULL。
2.5 QSqlError
QSqlError
是Qt SQL模块中的一个类,它用于表示数据库操作过程中可能出现的错误。当你在使用Qt的数据库操作功能时,如果出现问题,比如连接失败、查询错误等,可以通过QSqlError
对象获取具体的错误信息。
解决QSqlError
报错问题的步骤通常包括:
检查QSqlError
对象的文本描述,了解错误的具体信息。
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("mydb");
db.setUserName("user");
db.setPassword("password");
if (!db.open()) {
QSqlError error = db.lastError();
qDebug() << "数据库连接失败:" << error.text();
// 处理错误,如显示给用户,记录日志等
} else {
// 数据库操作
在这个例子中,如果数据库连接失败,db.open()
会返回false
,通过db.lastError()
获取到QSqlError
对象,并输出错误信息。根据错误信息,进行相应的处理。
3. SQL模型类
Qt除了提供QSqlQuery
实例对数据库通过exec()
执行sql语句进行操作之外,还提供基于QSqlTableModel
的模型处理方式,QSqlTableModel
与tableView
结合使用(model/view)。
Qt还提供了3个更高层的类来访问数据库,分别是QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。
这3个类都是从QAbstractTableModel派生来的,可以很容易地实现将数据库中的数据在QListView和QTableView等项视图类中进行显示。使用这些类的另一个好处是,这样可以使编写的代码很容易的适应其他的数据源。例如,如果开始使用了QSqlTableModel,而后来要改为使用XML文件来存储数据,这样需要做的仅是更换一个数据模型
3.1 QSqlQueryModel模型
QSqlQueryModel类为SQL结果集提供了只读数据模型。
QSqlQueryModel是执行SQL语句和遍历结果集的高级接口。 它构建在较低级别的QSqlQuery之上,可用于向视图类(如QTableView)提供数据。
QSqlQueryModel *sqlQueryModel = new QSqlQueryModel(this);
//sqlQueryModel->setQuery(query);
sqlQueryModel->setQuery("select * from user",database);
QTableView * view = new QTableView;
view->setModel(sqlQueryModel);
view->show();
我们设置了模型的查询,然后设置了显示在视图头中的标签。
QSqlQueryModel也可以用于通过编程方式访问数据库,而无需将其绑定到视图:
QSqlQueryModel model;
model.setQuery("SELECT username,nickname FROM user");
QString nickname = model.record(4).value("nickname").toInt();
上面的代码片段从SELECT查询结果集中的记录4中提取nickname字段。 由于nickname是第3列(索引为2),我们可以重写最后一行如下:
QString nickname = model.data(model.index(4,2)).toInt();
默认情况下,模型是只读的。 要使它可读可写,必须子类化它并重新实现setData()和flags()。 另一种选择是使用QSqlTableModel,它提供了基于单个数据库表的读写模型。
如果数据库不返回查询中选择的行数,模型将以递增的方式获取行。
//清除模型并释放所有获得的资源。
virtual void clear()
//返回关于数据库上发生的最后一个错误的信息
QSqlError lastError() const
//返回与此模型关联的QSqlQuery。
QSqlQuery query() const
//返回包含有关当前查询字段信息的记录。 如果row是有效行的索引,则记录将使用来自该行的值填充。
QSqlRecord record(int row) const
QSqlRecord record() const
//执行给定数据库连接db的查询查询。 如果没有指定数据库(或无效的数据库),则使用默认连接。
void setQuery(const QSqlQuery &query)
void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase())
3.2 QSqlTableModel模型
QSqlTableModel类为单个数据库表提供了一个可编辑的数据模型
QSqlTableModel是一个高级接口,用于从单个表中读写数据库记录。可用于向视图类(如QTableView)提供数据。 例如:
//构造时指定数据库,如果使用默认连接则不需要指定
QSqlTableModel* sqltableModel = new QSqlTableModel(this,database);
//设置需要查询的表名
sqltableModel->setTable("freecustomers");
//设置在视图中编辑值时选择的策略。 OnManualSubmit手动提交
sqltableModel->setEditStrategy(QSqlTableModel::EditStrategy::OnManualSubmit);
//使用指定的过滤器和排序条件,用setTable()设置的表中的数据填充模型,如果成功则返回true; 否则返回false。
sqltableModel->select();
//设置表头数据
sqltableModel->setHeaderData(0,Qt::Horizontal,"ID");
sqltableModel->setHeaderData(1,Qt::Horizontal,"QQ");
sqltableModel->setHeaderData(2,Qt::Horizontal,"电话");
QTableView * tableView = new QTableView;
tableView->setModel(sqltableModel);
tableView->hideColumn(0); //隐藏ID
tableView->show();
QSqlTableModel不提供对外键的直接支持。 如果要解析外键,请使用QSqlRelationalTableModel和QSqlRelationalDelegate。
//还原指定行的更改
virtual void revertRow(int row)
////设置在视图中编辑值时选择的策略。
virtual void setEditStrategy(QSqlTableModel::EditStrategy strategy)
//将当前筛选器设置为筛选器。这个过滤器是一个没有关键字WHERE的SQL WHERE子句(例如,name='Josephine')。
virtual void setFilter(const QString &filter)
//设置一条记录到指定行,记录顺序可以随意,会自动映射
bool setRecord(int row, const QSqlRecord &values)
bool insertRecord(int row, const QSqlRecord &record)
//将列的排序顺序设置为order。 这不会影响当前数据,要使用新的排序顺序刷新数据,调用select()。(在查询之前设置即可)
virtual void setSort(int column, Qt::SortOrder order)
//将模型操作的数据库表设置为tableName。 如果设置之后不调用select,那么将获取表的字段信息,要获取数据,必须调用select
virtual void setTable(const QString &tableName)
//获取表名
QString tableName() const
//获取一条空记录,只有字段名。 此函数可用于检索记录的字段名。
QSqlRecord record() const
//获取指定行的记录,如果row是有效行的索引。 如果模型没有初始化,将返回一个空记录。
QSqlRecord record(int row) const
//返回当前表的主键,如果表没有设置或没有主键,则返回空QSqlIndex。
QSqlIndex primaryKey() const
//如果模型包含未提交到数据库的修改值,则返回true,否则返回false。
bool isDirty(const QModelIndex &index) const
bool isDirty() const
signals
//在删除某一行之前会发出这个信号
void beforeDelete(int row)
//在插入某一条记录之前会发出这个信号,可以在插入之前修改记录 (这里是使用insertRow() 或 setData() 插入非空数据时发出的)
void beforeInsert(QSqlRecord &record)
//在更新某一行记录之前发出此信号。
void beforeUpdate(int row, QSqlRecord &record)
//准备插入一条记录是时,insertRows()将发出此信号。 可以将记录参数写入(因为它是一个引用),例如用默认值填充某些字段,并设置字段的生成标志(这里是使用insertRows()插入多个空行时发出的,一次插入多条,那么每一条记录就会发出一次信号)
void primeInsert(int row, QSqlRecord &record)
slots
//当用户取消编辑当前行时,项目委托将调用这个重新实现的槽。 如果模型的策略设置为OnRowChange或OnFieldChange,则恢复更改。 对OnManualSubmit策略不做任何操作。 使用revertAll()来恢复OnManualSubmit策略的所有挂起的更改,或使用revertRow()来恢复特定的行。
virtual void revert() override
//恢复所有待提交的更改
void revertAll()
//使用指定的过滤器和排序条件,用setTable()设置的表中的数据填充模型,如果成功则返回true; 否则返回false。
virtual bool select()
//刷新某一行,按主键匹配,如果没有主键,那么每一个字段都必须对应(重新从数据库中查询一行)
virtual bool selectRow(int row)
//使用submitAll()提交OnManualSubmit策略中所有挂起的更改。 成功返回true; 否则返回false。 使用lastError()查询详细的错误信息。 不会自动重新填充模型。 成功时将从数据库刷新提交的行。
virtual bool submit() override
//提交所有挂起的更改并在成功时返回true。 错误返回false,详细的错误信息可以通过lastError()获得。
//注意:在OnManualSubmit模式下,当submitAll()失败时,已经提交的更改不会从缓存中清除。 这允许在不丢失数据的情况下回滚和重新提交事务。
bool submitAll()
3.3 QSqlRelationalTableModel模型
QSqlRelationalTableModel的作用类似于QSqlTableModel,但允许将列设置为其他数据库表的外键。
左边的截图显示了一个普通的QTableView中的QSqlTableModel。 外键(城市和国家)不能解析为人类可读的值。 右边的屏幕截图显示了一个QSqlRelationalTableModel,外键被解析为人类可读的文本字符串。
QSqlRelationalTableModel* relationalModel = new QSqlRelationalTableModel(this,database);
relationalModel->setTable("freecustomers");
relationalModel->setRelation(1,QSqlRelation("lectures","qq","nickname"));
relationalModel->select();
调用setRelation()函数建立两个表之间的关系。 调用指定表freecustomers中的第1列是与表lectures的字段qq映射的外键,并且视图应该向用户显示城市的名称字段。 (把freecustomers表中第一列(qq字段),换成lectures表中qq与nickname对应的字段)
如果使用可读可写的QSqlRelationalTableModel,则可能需要在视图上使用QSqlRelationalDelegate。 与默认委托不同,QSqlRelationalDelegate为作为其他表的外键的字段提供了一个组合框。 要使用该类,只需在视图中调用QAbstractItemView::setItemDelegate(),并使用QSqlRelationalDelegate的实例:
QTableView * tableView = new QTableView;
tableView->setModel(relationalModel);
tableView->setItemDelegate(new QSqlRelationalDelegate(this));
tableView->show();
//设置SQL joinMode以显示或隐藏具有NULL外键的行。 在InnerJoin模式(默认)中,这些行不会显示:如果您想显示它们,请使用LeftJoin模式。
void setJoinMode(QSqlRelationalTableModel::JoinMode joinMode)
//让指定的列是relation指定的外部索引。
virtual void setRelation(int column, const QSqlRelation &relation)
4. SQL程序打包
使用了mysql数据库的程序,打包之后需要把mysql数据库bin目录下面的libcrypto-1_1-x64.dll和libssl-1_1-x64.dll
两个动态库拷贝到可执行程序的同级目录。
以及lib目录下面的libmysql.dll
也要拷贝进去,如果bin目录下不存在libcrypto-1_1-x64.dll和libssl-1_1-x64.dll
那就不用拷贝进去了。
没有打包进去的运行结果:
打包进去后的运行结果: