Qt SQL
Qt中的Qt SQL模块提供了对数据库的支持,模块中类可分为三层:驱动层,sql接口层,用户层。
驱动层:(QSqlDriver,QSqlDriverCreator,QSqlDriverCreatorBase,QSqlDriverPlugin)为具体的数据库和SQL接口层之间提供了底层的桥梁;
sql接口层:(QSqlDatabase,QSqlQuery,QSqlError,QSqlRecord)提供了对数据库的访问,其中QSqlDatabase类用来创建连接,QSqlQuery类可以使用SQL语句来实现与数据库交互;
用户接口层:(QSqlTableModel,QSqlQueryModel,QSqlRelationalTableModel)实现了将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,它们是更高层次的抽象;
1.数据库驱动
Qt SQL模块使用数据库驱动插件来和不同的数据库接口进行通信。由于Qt SQL模块的接口是独立于数据库的,所以所有数据库特定的代码都包含在了这些驱动中。Qt默认支持一些驱动:
驱动名称 |
数据库 |
QSQLITE2 |
SQLite2版本 |
QSQLITE |
SQLite3版本 |
QMYSQL |
MySQL |
QODBC |
SQL Service |
QPSQL |
PostgreSQL(>=7.3版本) |
【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取
2.查询驱动
qDebug()<<"数据库驱动:"<<QSqlDatabase::drivers();//查看QT支持的数据库驱动
3.连接数据库
QSqlDatabase类提供了一个通过连接访问数据库的接口。 QSqlDatabase的一个实例表示连接。 该连接通过一个受支持的数据库驱动程序提供对数据库的访问,该驱动程序派生自QSqlDriver。
通过调用一个静态addDatabase()函数创建一个连接,在该函数中指定要使用的驱动程序或驱动程序类型(取决于数据库的类型)和一个连接名称。 连接可以通过它自己的名称而不是它所连接的数据库的名称得知。 可以有一个或多个数据库的连接。 QSqlDatabase还支持默认连接的概念,即未命名连接。 要创建默认连接,在调用addDatabase()时不要传递连接名称参数。 随后,如果您调用任何静态成员函数而没有指定连接名,则将假定默认连接。
下面的代码片段展示了如何创建和打开到MySQL数据库的默认连接:
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");//添加一个数据库db.setHostName("127.0.0.1"); //设置数据库的主机ipdb.setPort(3306); //设置端口 db.setDatabaseName("mydb"); //设置数据库的名字db.setUserName("root"); //设置数据库的用户名db.setPassword("123456"); //设置数据库的密码bool ok = db.open(); //打开数据库
注意:如果提示驱动未加载,则需要编译驱动,并配置一下
QSqlDatabase: QMYSQL driver not loadedQSqlDatabase: available drivers: QSQLITE QODBC QODBC3 QPSQL QPSQL7
创建QSqlDatabase对象之后,使用setDatabaseName()、setUserName()、setPassword()、setHostName()、setPort()和setConnectOptions()设置连接参数。 然后调用open()来激活到数据库的物理连接。 在您打开连接之前,该连接不可用。
上面定义的连接将是默认连接,因为我们没有给addDatabase()提供连接名。 随后,你可以通过调用database()不带连接名称参数来获得默认连接:
QSqlDatabase db = QSqlDatabase::database();
QSqlDatabase是一个值类。 通过一个QSqlDatabase实例对数据库连接所做的更改将影响表示同一连接的其他QSqlDatabase实例。 使用cloneDatabase()在现有数据库连接的基础上创建一个独立的数据库连接。
警告:强烈建议不要将QSqlDatabase的副本作为类的成员保存,因为这将阻止在关闭时正确清理实例。 如果需要访问现有的QSqlDatabase,应该使用database()来访问它。 如果你选择有一个QSqlDatabase成员变量,它需要在QCoreApplication实例被删除之前被删除,否则它可能会导致未定义的行为。
如果创建多个数据库连接,在调用addDatabase()时为每个连接指定唯一的连接名。 使用带有连接名的database()来获取该连接。 使用removeDatabase()和连接名一起删除连接。 如果您试图删除由其他QSqlDatabase对象引用的连接,QSqlDatabase将输出一个警告。 使用contains()查看给定的连接名是否在连接列表中。
一些实用方法:
函数 |
描述 |
QStringList tables() |
返回数据库中所有的表列表 |
QSqlRecord QSqlDatabase::record(const QString &tablename) |
返回一条记录(改记录只包含字段,没有数据) |
bool QSqlDatabase::transaction() |
开启事务 |
bool QSqlDatabase::commit() |
提交事务 |
bool QSqlDatabase::rollback() |
回滚事务 |
bool QSqlDriver::hasFrature() |
检查驱动程序是否支持事务 |
QSqlError QSqlDatabase::lastError() |
返回数据库上发生的最后一个错误的信息。 |
[static] QStringList QSqlDatabase::drivers() |
返回可用SQL驱动程序的名称 |
[static] bool QSqlDatabase::isDriverAvailable(const QString &name) |
检查某个特定的驱动程序是否可用 |
4.QSqlRecord
QSqlRecord类封装了数据库记录(通常是数据库中的表或视图中的一行)的功能和特征。 QSqlRecord支持添加和删除字段,以及设置和检索字段值。
使用setValue()可以通过名称或位置设置记录字段的值; 如果你想设置一个字段值为空,使用setNull()。 要按名称查找字段的位置,请使用indexOf(),要在特定位置查找字段的名称,请使用fieldName()。 使用field()检索给定字段的QSqlField对象。 使用contains()查看记录是否包含特定的字段名。
当生成要在数据库上执行的查询时,生成的SQL中只包含isGenerated()为true的字段。
一条记录可以有通过append()或insert()添加的字段,通过replace()替换的字段,以及通过remove()删除的字段。 可以使用clear()删除所有字段。 字段的数量由count()给出; 所有它们的值都可以使用clearValues()清除(为空)。
对SqlRecord记录字段操作不会影响到原来的表。
下面的代码片段展示了如何获取指定表的所有字段,只不过值是无效的。
QSqlRecord rec = db.record("emp");for (int i=0;i<rec.count();i++){ qDebug()<<rec.fieldName(i)<<rec.value(i);}
5.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");
【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取
6.QSqlQuery
QSqlQuery封装了从在QSqlDatabase上执行的SQL查询中创建、导航和检索数据所涉及的功能。 它可以用于执行DML(数据操作语言)语句,如SELECT、INSERT、UPDATE和DELETE,也可以用于执行DDL(数据定义语言)语句,如CREATE TABLE。 它也可以用于执行非标准SQL的特定数据库命令。
成功执行的SQL语句将查询的状态设置为活动,以便isActive()返回true。 否则,查询的状态将设置为不活动。 在这两种情况下,当执行新的SQL语句时,查询将定位在无效的记录上。 在检索值之前,活动查询必须导航到有效记录(以便isValid()返回true)。
导航记录有以下功能:
bool next() //检索结果中的下一条记录(如果可用),并在检索的记录上定位查询。bool previous() //检索结果中的前一条记录(如果可用),并将查询定位于检索的记录上。 bool first() //检索结果中的第一条记录(如果可用),并在检索的记录上定位查询。 bool last() //检索结果中的最后一条记录(如果可用),并在检索的记录上定位查询 bool seek() //在位置索引处检索记录(如果可用),并在检索的记录上定位查询。 第一条记录位于位置0。int at() const //返回查询的当前内部位置。 如果位置无效,函数返回特殊的负值QSql::BeforeFirstRow或QSql::AfterLastRow。
这些函数允许程序员在查询返回的记录中向前、向后移动或任意移动。 如果您只需要移动结果(例如,使用next()),您可以使用setForwardOnly(),这将节省大量的内存开销,并提高某些数据库的性能。 一旦活动查询定位在有效记录上,就可以使用value()检索数据。 所有数据都使用qvariant从SQL后端传输。
例如:
QSqlQuery query("SELECT ename FROM emp");while (query.next()) { QString ename = query.value(0).toString(); QString ename = query.value("ename").toString(); qDebug()<< ename;}
要访问查询返回的数据,请使用value(int)。 通过从0开始传递字段在语句中的位置来访问SELECT语句返回的数据中的每个字段。 这使得使用SELECT *查询是不可取的,因为返回的字段的顺序是不确定的。
下面代码片段可以获取指定表的所有记录:
QSqlQuery query("SELECT * FROM emp");auto record = query.record();while (query.next()){ for (int i = 0;i<record.count();i++) { QString ename = query.value(i).toString(); std::cout<< ename.toStdString()<<"t"; } std::cout<<std::endl; }
int QSqlQuery::size() const
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支持这两种语法,只是不能将它们混合在同一个查询中。
6.1绑定值
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();
QSqlQuery query; query.prepare("INSERT INTO user (id, username, nickname)" "VALUES (?,?,?)"); query.bindValue(0,520); query.bindValue(1,"maye"); query.bindValue(2,"顽石"); query.exec();
QSqlQuery query; query.prepare("INSERT INTO user (id, username, nickname)" "VALUES (?,?,?)"); query.addBindValue(520); query.addBindValue("maye"); query.addBindValue("顽石"); query.exec();
另外,未绑定的参数将导致操作失败。
【领QT开发教程学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取
6.2批处理操作
方式一: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中混合整数和字符串变量。
SQL模型类
Qt还提供了3个更高层的类来访问数据库,分别是QSqlQueryModel、QSqlTableModel和QSqlRelationalTableModel。
这3个类都是从QAbstractTableModel派生来的,可以很容易地实现将数据库中的数据在QListView和QTableView等项视图类中进行显示。使用这些类的另一个好处是,这样可以使编写的代码很容易的适应其他的数据源。例如,如果开始使用了QSqlTableModel,而后来要改为使用XML文件来存储数据,这样需要做的仅是更换一个数据模型
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) constQSqlRecord record() const//执行给定数据库连接db的查询查询。 如果没有指定数据库(或无效的数据库),则使用默认连接。 void setQuery(const QSqlQuery &query)void setQuery(const QString &query, const QSqlDatabase &db = QSqlDatabase())
2.QSqlTableModel模型
QSqlTableModel是一个高级接口,用于从单个表中读写数据库记录。可用于向视图类(如QTableView)提供数据。 例如:
QSqlTableModel不提供对外键的直接支持。 如果要解析外键,请使用QSqlRelationalTableModel和QSqlRelationalDelegate。
其他函数
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!