Qt:数据库编程

包含头文件 #include <QtSql>
在工程的.pro文件中加入 QT += sql
一、连接数据库
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL","ConnA");//驱动名,连接名
    db.setHostName("music");
    db.setDatabaseName("qt532");
    db.setUserName("mysql");
    db.setPassword("mysql");
    db.open();    //打开数据库连接
二、操作数据库
1、查询:
    QSqlQuery query;
    query.exec("SELECT title,year FROM cd WHERE year >= 1998");
  //QSqlQuery query("SELECT title,year FROM cd WHERE year >= 1998");
  //可以通过对查询调用isActive()来检查是否有错误发生,若没有,查询会变成“激活”状态,可用next()
    if(!query.isActive())
        QMessageBox::warning(this,tr("Database error"),
                             query.lastError().text());
    while(query.next()){   //遍历查询结果
        QString title = query.value(0).toString();
        int year = query.value(1).toInt();
        std::cerr << qPrintable(title) << ":" << year << std::endl;
    }
2、插入:
   QSqlQuery query("INSERT INTO cd(id,artistid,title,year)"
                    "VALUES (203,102,"living",2002)");
//之后调用numRowsAffected()返回受SQL语句影响的行数(error,return -1)
* 插入多条记录(或想避免将数值转换成字符串):
//Oracle风格语法及命名占位符实例:
  QSqlQuery query;
  query.prepare("INSERT INTO cd(id,artistid,title,year)"
                  "VALUES (:id, :artistid, :title, :year)");
    query.bindValue(":id",203);
    query.bindValue(":artistid",102);
    query.bindValue(":title","Living");
    query.bindValue(":year",2002);
    query.exec();
//ODBC风格:
    QSqlQuery query;
    query.prepare("INSERT INTO cd(id,artistid,title,year)"
                  "VALUES (?,?,?,?)");
    query.addBindValue(203);
    query.addBindValue(102);
    query.addBindValue("Living");
    query.addBindValue(2002);
    query.exec();
//exec()调用之后,可以用bindValue()或addBindValue()来赋值绑定新值,然后再次调用exec()
//并利用这些新值进行查询.
3、更新操作:
query.exec("UPDATE cd SET artistid = 100 WHERE id = 30");
4、删除操作:
query.exec("DELETE FROM cd where id = 121");
三、事务操作:
发起一个事务操作:代表数据库连接的QSqlDatabase对象调用transaction()
结束一个事务操作:commit()或rollback()
    QSqlDatabase::database().transaction();
    QSqlQuery query;
    query.exec("SELECT id FROM artistid WHERE name = 'kaka'");
    if(query.next()){
        int artistId = query.value(0).toInt();
        query.exec("INSERT INTO cd(id,artistid,title,year)"
                   "VALUES(201,"+QString::number(artistId)
                   +",'Ride',1997)");
    }
    QSqlDatabase::database().commit();
测试数据库是否支持事务:
   QSqlDriver *driver = QSqlDatabase::database().driver();
   if(driver->hasFeature(QSqlDriver::Transactions))  .....
每连接一次只能处理一个活动的事务,对于希望一次执行多个事务的操作,建立多连接将十分有用。
/******************************************************************************************************/
除了QSqlQuery类,Qt还提供了三种用于访问数据库的高层类:
   QSqlQueryModel,QSqlTableModel,QSqlRelationalTableModel
1、QSqlQueryModel类提供了一个只读的数据模型用于表示SQL操作的结果:
    QSqlQueryModel model;
    model.setQuery("SELECT * FROM automobile");
    for(int i = 0; i < model.rowCount(); ++i){
        int carnumber = model.record(i).value("carnumber").toInt();
        QString kind = model.record(i).value("kind").toString();
        qDebug() << kind << carnumber;
    }
2、QSqlTableModel 提供了一个可读写的数据模型用于操作单个SQL表:
    QSqlTableModel model;
    model.setTable("automobile");
    model.setFilter("price > 120");
    model.select();
    //等价于SELECT * FROM automobile WHERE price > 120
    for(int i = 0; i < model.rowCount(); ++i){
        QString kind = model.record(i).value("kind").toString();
        int carnumber = model.record(i).value("carnumber").toInt();
        qDebug() << kind << carnumber;
    }
    //操作大数据集时,建议通过索引指定字段:
    int kindIndex = model.record().indexOf("kind");
    int carIndex = model.record().indexOf("carnumber");
    for(int i = 0; i < model.rowCount(); ++i){
        QSqlRecord record = model.record(i);
        QString kind = record.value(kindIndex).toString();
        int carnumber = record.value(carIndex).toInt();
        qDebug() << kind << carnumber;
    }
为了在数据库表中插入记录,可调用insertRow()来创建一个新的空行,然后使用setData设置每一个列的值:
    QSqlTableModel model;
    model.setTable("cd");
    int row = 0;
    model.insertRows(row,1);
    model.setData(model.index(row,0),113);
    model.setData(model.index(row,1),"shanghai");
    model.setData(model.index(row,2),224);
    model.setData(model.index(row,3),2003);
    model.submitAll();
为了更新某一记录,首先必须把QSqlTableModel定位到要修改的记录上(如select),然后提取这条记录,
更新想改变的字段并将更改过的数据回写到数据库中:
    QSqlTableModel model;
    model.setTable("cd");
    model.select();
    if(model.rowCount() == 1){
        QSqlRecord record = model.record(0);
        record.setValue("title","sea");
        record.setValue("year",record.value("year").toInt() + 1);
        model.setRecord(0,record);
      //model.removeRows(0,1); //要删除的行号,行数
        model.submitAll();
    }
/*  if(model.rowCount() > 0){
model.removeRows(0,model.rowCount());
model.submitAll();
    }  */
3、QSqlRelationalTableModel是对QSqlTableMode的扩展,它提供对外键的支持:
    QSqlRelationalTableModel model;
    model.setTable("cars");
    model.setRelation(2,QSqlRelation("factory","id","name"));
    //cars表中2(factoryid)字段是factory表中id字段的外键,但显示为factory表中的name字段
/////////////////////////////////////////////////////////////////////////////////////////
这三个类均可以作为数据源在Qt的视图类中表示,如QListView,QTableView,QTreeView:
    QTableView *view = new QTableView;
    view->setModel(model);
    view->show();
    model->setHeaderData(0,Qt::Horizontal,QObject::tr("ID"));
    model->setHeaderData(1,Qt::Horizontal,QObject::tr("品牌"));
    model->setHeaderData(2,Qt::Horizontal,QObject::tr("产家"));
    model->setHeaderData(3,Qt::Horizontal,QObject::tr("时间"));
对于可读写的模型类QSqlTableModel和QSqlRelationalTableModel,视图允许用户编辑其中的字段,
也可以禁止用户编辑:
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
可以将同一个数据模型用于多个视图,一旦用户通过其中某个视图编辑了数据模型,其他视图也会立即更新。
*虽然QSqlTableModel对单个表的操作进行了优化并提供了读写支持,但如果用户希望对任意的数据库操作结果
集进行更大程度的灵活控制,可以直接从QSqlTableModel的基类QSqlQueryModel继承,并通过重写flags()函数
和setData()函数将其变为可读写的。            
//为查询模型的“字段3”增加可写属性,但保持其他字段只读属性不变:
Qt::ItemFlags EditableModel::flags(const QModelIndex &index) const{
Qt::ItemFlags flags = QSqlQueryModel::flags(index);
if(index.column() == 3)
flags |= Qt::ItemIsEditable;
return flags;
}
bool EditableModel::setData(const QModelIndex &index,const QVariant &value,int role){
if(index.column() != 3)
return false;
QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(),0);
int id = data(primaryKeyIndex).toInt();
clear();
bool ok;
ok = setName(id,value.toString());
refresh();
return ok;
} //修改了表中“字段3”的内容,然后刷新显示
bool EditableModel::setName(int personId,const QString &name){
QSqlQuery query;
query.prepare("update person set name = ? where id = ?");
query.addBindValue(name);
query.addBindValue(personId);
return query.exec();
}
/******************************************************************************************************/
//以一个控制台程序的形式,使用SQLite数据库完成大批量数据的增删改查操作,并打印其耗时。
#include <QCoreApplication>
#include <QTextCodec>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QTime>
#include <QSqlError>
#include <QDebug>
#include <QtSql>


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());


    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if(!db.open()){
        qDebug()<<QObject::tr("打开数据库失败");
        return false;
    }
    QSqlQuery query;
    bool bSuccess = query.exec("CREATE TABLE automobil(id INT PRIMARY KEY,"
                               "attribute VARCHAR,"
                               "type VARCHAR,"
                               "kind VARCHAR,"
                               "nation INT,"
                               "carnumber INT,"
                               "elevaltor INT,"
                               "distance INT,"
                               "oil INT,"
                               "temperature INT)");
    if(bSuccess)
        qDebug()<<QObject::tr("数据库表创建成功!\n");
    else
        qDebug()<<QObject::tr("数据库表创建失败\n");
    QTime t;
    t.start();
    query.prepare("INSERT INTO automobil"
                  "VALUES(?,?,?,?,?,?,?,?,?,?)");
    long records = 10000;
    for(int i = 0; i < records; ++i){
        query.bindValue(0,i);
        query.bindValue(1,"奔驰");
        query.bindValue(2,"宝马");
        query.bindValue(3,"奥迪");
        query.bindValue(4,rand()%100);
        query.bindValue(5,rand()%10000);
        query.bindValue(6,rand()%300);
        query.bindValue(7,rand()%20000);
        query.bindValue(8,rand()%52);
        query.bindValue(9,rand()%100);
        bSuccess = query.exec();
        if(!bSuccess){
            QSqlError lastError = query.lastError();
            qDebug()<<lastError.driverText()<<QString(QObject::tr("插入失败"));
        }
    }
    qDebug()<<QObject::tr("插入 %1 条记录,耗时:%2 ms").arg(records).arg(t.elapsed());


    t.restart();
    bSuccess = query.exec("SELECT * FROM automobil ORDER BY id DESC");
    if(bSuccess){
        qDebug()<<QObject::tr("排序 %1 条记录,耗时:%2 ms").arg(records).arg(t.elapsed());


    }else{
        qDebug()<<QObject::tr("排序失败!");
    }


    t.restart();
    for(int i = 0; i < records; ++i){
        query.clear();
        query.prepare(QString("UPDATE automobil SET"
                              "attribute=?,type=?,kind=?,"
                              "nation=?,carnumber=?,elevaltor=?,"
                              "distance=?,oil=?,temperature=?"
                              "WHERE id=%1").arg(i));
        query.bindValue(0,i);
        query.bindValue(0,"奔驰");
        query.bindValue(1,"宝马");
        query.bindValue(2,"奥迪");
        query.bindValue(3,rand()%100);
        query.bindValue(4,rand()%10000);
        query.bindValue(5,rand()%300);
        query.bindValue(6,rand()%200000);
        query.bindValue(7,rand()%52);
        query.bindValue(8,rand()%100);
        bSuccess = query.exec();
        if(!bSuccess){
            QSqlError lastError = query.lastError();
            qDebug()<<lastError.driverText()<<QString(QObject::tr("更新失败"));
        }
    }
    qDebug()<<QObject::tr("更新 %1 条记录,耗时 %2 ms").arg(records).arg(t.elapsed());


    t.restart();
    query.exec("DELETE FROM automobil WHERE id = 1500");
    qDebug()<<QObject::tr("删除一条记录,耗时 %1 ms").arg(t.elapsed());


    return a.exec();


}
 
 
posted @ 2017-09-20 12:40  jeffkuang  阅读(424)  评论(0)    收藏  举报