Qt数据库操作

1. 建立连接:

QSqlDatabase,是一个值类,一个实例代表一个连接。 下面是支持的数据库:

Driver name	DBMS
QDB2	IBM DB2 (version 7.1 and above)
QIBASE	Borland InterBase
QMYSQL	MySQL
QOCI	Oracle Call Interface Driver
QODBC	Open Database Connectivity (ODBC) - 
		Microsoft SQL Server and other ODBC-compliant databases
QPSQL	PostgreSQL (versions 7.3 and above)
QSQLITE2	SQLite version 2
QSQLITE	SQLite version 3
QTDS	Sybase Adaptive Server
Note: obsolete from Qt 4.7

建立连接方法一:使用静态方法 addDatabase(),并用打开open():

QSqlDatabase db = QSqlDatabase::addDatabase("QPSQL");
db.setHostName("acidalia");
db.setDatabaseName("customdb");
db.setUserName("mojito");
db.setPassword("J0a1m8");
bool ok = db.open();

方法二:使用默认,使用tables()查看数据库中的表.使用record(),查看字段。

QSqlDatabase db = QSqlDatabase::database();

示例:

void ConnectionWidget::refresh()
{
    tree->clear();
    QStringList connectionNames = QSqlDatabase::connectionNames();

    bool gotActiveDb = false;
    for (int i = 0; i < connectionNames.count(); ++i) {
        QTreeWidgetItem *root = new QTreeWidgetItem(tree);
        QSqlDatabase db = QSqlDatabase::database(connectionNames.at(i), false);
        root->setText(0, qDBCaption(db));
        if (connectionNames.at(i) == activeDb) {
            gotActiveDb = true;
            setActive(root);
        }
        if (db.isOpen()) {
            QStringList tables = db.tables();
            for (int t = 0; t < tables.count(); ++t) {
                QTreeWidgetItem *table = new QTreeWidgetItem(root);
                table->setText(0, tables.at(t));
            }
        }
    }
    if (!gotActiveDb) {
        activeDb = connectionNames.value(0);
        setActive(tree->topLevelItem(0));
    }

}

//显示表格字体详情
void Browser::showMetaData(const QString &t)
{
    QSqlRecord rec = connectionWidget->currentDatabase().record(t);
    QStandardItemModel *model = new QStandardItemModel(table);

    model->insertRows(0, rec.count());
    model->insertColumns(0, 7);

    model->setHeaderData(0, Qt::Horizontal, "Fieldname");
    model->setHeaderData(1, Qt::Horizontal, "Type");
    model->setHeaderData(2, Qt::Horizontal, "Length");
    model->setHeaderData(3, Qt::Horizontal, "Precision");
    model->setHeaderData(4, Qt::Horizontal, "Required");
    model->setHeaderData(5, Qt::Horizontal, "AutoValue");
    model->setHeaderData(6, Qt::Horizontal, "DefaultValue");


    for (int i = 0; i < rec.count(); ++i) {
        QSqlField fld = rec.field(i);
        model->setData(model->index(i, 0), fld.name());
        model->setData(model->index(i, 1), fld.typeID() == -1
                ? QString(QMetaType::typeName(fld.type()))
                : QString("%1 (%2)").arg(QMetaType::typeName(fld.type())).arg(fld.typeID()));
        model->setData(model->index(i, 2), fld.length());
        model->setData(model->index(i, 3), fld.precision());
        model->setData(model->index(i, 4), fld.requiredStatus() == -1 ? QVariant("?")
                : QVariant(bool(fld.requiredStatus())));
        model->setData(model->index(i, 5), fld.isAutoValue());
        model->setData(model->index(i, 6), fld.defaultValue());
    }

    table->setModel(model);
    table->setEditTriggers(QAbstractItemView::NoEditTriggers);

    updateActions();
}

###2.执行SQL: QT中的数据库操作,使用QSqlQuery进行增删改查。

bool QSqlQuery::exec(const QString & query)

对于SQLite, SQL语句只能一次执行一条,多的会执行失败。可以通过循环的方式来多次执行。

Example:

QSqlQuery query;
query.exec("INSERT INTO employee (id, name, salary) "
           "VALUES (1001, 'Thad Beaumont', 65000)");

错误信息:

QSqlError QSqlQuery::lastError () const 返回最后产生的错误信息。

###3.批量执行

可以用绑定进行,多条相同结构的SQL语句:

QSqlQuery q;
q.prepare("insert into myTable values (?, ?)");

QVariantList ints;
ints << 1 << 2 << 3 << 4;
q.addBindValue(ints);

QVariantList names;
names << "Harald" << "Boris" << "Trond" << QVariant(QVariant::String);
q.addBindValue(names);

if (!q.execBatch())
    qDebug() << q.lastError();

结果插入4条记录
1  Harald
2  Boris
3  Trond
4  NULL

###4.结果集:

执行的结果,在QSqlRecord中,每一个QSqlRecord为一条记录。使用next()遍历结果集,其它操作还有

seek(int n) :query指向结果集的第n条记录;
first() :query指向结果集的第一条记录;
last() :query指向结果集的最后一条记录;
next() :query指向下一条记录,每执行一次该函数,便指向相邻的下一条记录;
previous() :query指向上一条记录,每执行一次该函数,便指向相邻的上一条记录;
record() :获得现在指向的记录;
value(int n) :获得字段的值。其中n表示你查询的第n个字段,
	“select id, name from student”,
	那么value(0)返回id字段的值,value(1)返回name字段的值。
at() :获得现在query指向的记录在结果集中的编号。

例子:

QSqlQuery q("select * from employees");
QSqlRecord rec = q.record();
qDebug() << "Number of columns: " << rec.count();
int nameCol = rec.indexOf("name"); // index of the field "name"
while (q.next())
    qDebug() << q.value(nameCol).toString(); // output all names

###5.事务操作

bool QSqlDatabase::transaction() 返回TRUE,表示支持成功,否则失败。

事务可以保证一个复杂的操作的原子性。在Qt中,如果底层的数据库引擎支持事务,那么QSqlDriver::hasFeature(QSqlDriver::Transactions)会返回true。

使用QSqlDatabase::transaction()来启动一个事务,然后编写一些希望在事务中执行的SQL语句,最后调用QSqlDatabase::commit()或者QSqlDatabase::rollback()。

当使用事务时必须在创建查询以前就开始事务,例如:

QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
if (query.next()) {
    int employeeId = query.value(0).toInt();
    query.exec("INSERT INTO project (id, name, ownerid) "
               "VALUES (201, 'Manhattan Project', "
               + QString::number(employeeId) + ')');
}
QSqlDatabase::database().commit();

###6.移除数据库

使用removeDatabase删除建立的连接:

{
    QSqlDatabase db = QSqlDatabase::database("sales");
    QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db);
}
// Both "db" and "query" are destroyed because they are out of scope
QSqlDatabase::removeDatabase("sales"); // correct

参考:

  1. my coding.net
  2. 定义
  3. 第23篇 Qt5之数据库(三)利用QSqlQuery类执行SQL语句