zoukankan      html  css  js  c++  java
  • Qt数据库操作(qt-win-commercial-src-4.3.1,VC6,Oracle,SQL Server)

    qt-win-commercial-src-4.3.1、qt-x11-commercial-src-4.3.1
    Microsoft Visual C++ 6.0、KDevelop 3.5.0
    Windows Xp、Solaris 10、Fedora 8
    SQL Server、Oracle 10g Client

    ■、驱动编译
    这里要提及两个数据库驱动,分别是ODBC和OCI

    Windows操作系统中编译ODBC驱动:
    执行以下命令,会在%QTDIR%pluginssqldrivers目录下面生成qsqlodbc4.dll。

    cd %QTDIR%srcpluginssqldriversodbc
    qmake -o Makefile odbc.pro
    nmake

    Unix操作系统下编译unixODBC驱动:
    unixODBC可以在
    http://www.unixodbc.org下载。这里假定unixODBC安装在/usr/local/unixODBC。
    执行以下命令,会在$QTDIR/plugins/sqldrivers目录下面生成qsqlodbc4.a。

    cd $QTDIR/src/plugins/sqldrivers/odbc
    qmake "INCLUDEPATH+=/usr/local/unixODBC/include" "LIBS+=-L/usr/local/unixODBC/lib -lodbc"
    make

    Windows操作系统中编译OCI驱动:
    这里假定Oracle Client安装在C:oracle。添加oci.dll动态连接库的环境变量c:oraclein。

    set INCLUDE=%INCLUDE%;c:oracleociinclude
    set LIB=%LIB%;c:oracleocilibmsvc
    cd %QTDIR%srcpluginssqldriversoci
    qmake -o Makefile oci.pro
    nmake

    Unix操作系统下编译OCI驱动:
    当然根据你的oracle修正下相应的版本号。

    cd $QTDIR/src/plugins/sqldrivers/oci
    qmake -o Makefile "INCLUDEPATH+=/usr/include/oracle/10.1.0.3/client/" "LIBS+=-L/usr/lib/oracle/10.1.0.3/client/lib" oci.pro
    make

    在程序中包含头文件
        #include <QtSql>
    在程序的.pro文件中添加
        QT += sql


    ■、数据库连接
    这里则要提及单一数据库连接和多个数据库连接:

    单一数据库连接:

    static bool sqlConnection(const QString& HostName, 
                                             const QString& DatabaseName, 
                                             const QString& UserName, 
                                             const QString& Password)
    {
        QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
        db.setHostName(HostName);
        db.setDatabaseName(DatabaseName);
        db.setUserName(UserName);
        db.setPassword(Password);

        if(!db.open())
        {
            QMessageBox::critical(0, QObject::tr("Error"), 
                                                QObject::tr("The database reported an error: %1").arg(db.lastError().text()));
            return false;
        }
        //在Qt数据库连接后,运行"SET NAMES 'UTF8'"语句或"SET NAMES 'GBK'"。
        //db.exec("SET NAMES 'UTF8'");
        return true;
    }

    //多个数据库连接
    static bool sqlConnections()
    {
        // 创建一个名为odbc的连接
        QSqlDatabase *odbc = QSqlDatabase::addDatabase( "QODBC", "ODBC" );
        if ( ! defaultDB ) {
            qWarning( "Failed to connect to odbc driver" );
            return FALSE;
        }
        odbc->setDatabaseName( DB_ODBC_DBNAME );
        odbc->setUserName( DB_ODBC_USER );
        odbc->setPassword( DB_ODBC_PASSWD );
        odbc->setHostName( DB_ODBC_HOST );
        if ( ! odbc->open() ) {
            qWarning( "Failed to open sales database: " + odbc->lastError().driverText() );
            qWarning( odbc->lastError().databaseText() );
            return FALSE;
        }

        // 创建一个名为oracle的连接
        QSqlDatabase *oracle = QSqlDatabase::addDatabase( "QOCI", "ORACLE" );
        if ( ! oracle ) {
            qWarning( "Failed to connect to oracle driver" );
            return FALSE;
        }
        oracle->setDatabaseName( DB_ORACLE_DBNAME );
        oracle->setUserName( DB_ORACLE_USER );
        oracle->setPassword( DB_ORACLE_PASSWD );
        oracle->setHostName( DB_ORACLE_HOST );
        if ( ! oracle->open() ) {
            qWarning( "Failed to open orders database: " + oracle->lastError().driverText() );
            qWarning( oracle->lastError().databaseText() );
            return FALSE;
        }

        return TRUE;
    }

    QSqlDatabase维护着通过addDatabase()这个静态函数返回的的连接指针。
    如果有移去一个连接,先调用QSqlDatabase::close()来关闭连接,然后通过静态函数QSqlDatabase::removeDatabase()来移除连接。

    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
        QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
        QFont font("Times", 9, QFont::Normal, FALSE);
        app.setFont(font);

        //连接单一数据库
        if (!sqlConnection("10.0.0.3", "qjkzdb", "sa", "syth7777"))
            return 1;

        //连接多个数据库
        if (!sqlConnections())
            return 1;
        // 数据库被成功打开,得到它们的指针:
        QSqlDatabase *oracledb = QSqlDatabase::database( "ORACLE" );
        // 现在我们可以在oracle连接或默认连接上执行SQL命令
        ...

        return app.exec();
    }


    ■、SQL执行操作

    QSqlQuery提供了对数据库记录的Select、Insert、Update、Delete操作。

    SELECT操作:

    QSqlQuery query;
    query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
    while (query.next()) {
        QString name = query.value(0).toString();
        int salary = query.value(1).toInt();
        qDebug() << name << salary;
    }

    通过QSqlQuery::next()、QSqlQuery::previous()、QSqlQuery::first()、QSqlQuery::last()、QSqlQuery::seek(),
    可以得到下一条、上一条、第一条、最后一条、任意一条记录的位置。

    INSERT操作:

    //单一插入数据
    QSqlQuery query;
    query.prepare("INSERT INTO employee (id, name, salary) "
                            "VALUES (:id, :name, :salary)");
    query.bindValue(":id", 1001);
    query.bindValue(":name", "Thad Beaumont");
    query.bindValue(":salary", 65000);
    query.exec();

    //批量插入数据
    QSqlQuery query;
    query.prepare("insert into myTable values (?, ?)");

    QVariantList ints;
    ints << 1 << 2 << 3 << 4;
    query.addBindValue(ints);
    QVariantList names;
    names << "Harald" << "Boris" << "Trond" << QVariant(QVariant::String);
    query.addBindValue(names);

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

    UPDATE操作:

    QSqlQuery query;
    query.prepare("UPDATE employee SET salary = ? WHERE id = 1003");
    query.bindValue(0, 70000);
    query.exe();

    DELETE操作:

    QSqlQuery query;
    query.exec("DELETE FROM employee WHERE id = 1007");

    事务处理:

    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();

    如果数据库引擎支持事务处理,则函数QSqlDriver::hasFeature(QSqlDriver::Transactions)将返回 真。
    可以通过调用QSqlDatabase::transaction()来初始化一个事务处理。之后执行你想在该事务处理的工作。
    完了再执行QSqlDatabase::commit()来提交事务处理或QSqlDatabase::rollback()取消事务处理。

    这里在举个QSqlDriver::hasFeature(QSqlDriver::QuerySize)例子,可以较快的统计查询记录行数。

    QSqlQuery query;
    int numRows;
    query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
    QSqlDatabase defaultDB = QSqlDatabase::database();
    if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
        numRows = query.size();
    } else {
         // this can be very slow
         query.last();
         numRows = query.at() + 1;
    }

    存储过程:

    AsciiToInt()是数据库中的一个存储过程。
    但我在网上以前好像看过说是SQL Server中的存储过程是通过"EXEC"完成的,而不是"CALL",这里我不确定!留下一个疑问吧~

    QSqlQuery query;
    query.prepare("CALL AsciiToInt(?, ?)");
    query.bindValue(0, "A");
    query.bindValue(1, 0, QSql::Out);
    query.exec();
    int i = query.boundValue(1).toInt(); // i is 65


    ■、使用SQL Model类

    QSqlQueryModel:一个只读的读取数据库数据的模型。
    QSqlTableModel:一个可读写的单一表格模型,可以不用写SQL语句。
    QSqlRelationalTableModel:QSqlTableModel的一个子类,可多表关联在一起。
    这些类都继承于QAbstractTableModel,而它们又都继承于QAbstractItemModel。

    QSqlQueryModel 只读模式,基于SQL查询基础。

    QSqlQueryModel model;
    model.setQuery("SELECT * FROM employee");
    for (int i = 0; i < model.rowCount(); ++i) {
        int id = model.record(i).value("id").toInt();
        QString name = model.record(i).value("name").toString();
        qDebug() << id << name;
    }

    QSqlTableModel 可对单一表操作,进行读写操作。

    //读取数据
    QSqlTableModel model;
    model.setTable("employee");
    model.setFilter("salary > 50000");
    model.setSort(2, Qt::DescendingOrder);
    model.select();
    for (int i = 0; i < model.rowCount(); ++i) {
        QString name = model.record(i).value("name").toString();
        int salary = model.record(i).value("salary").toInt();
        qDebug() << name << salary;
    }
    //通过QSqlTableModel::setRecord()修改数据
    for (int i = 0; i < model.rowCount(); ++i) {
        QSqlRecord record = model.record(i);
        double salary = record.value("salary").toInt();
        salary *= 1.1;
        record.setValue("salary", salary);
        model.setRecord(i, record);
    }
    model.submitAll();
    //通过QSqlTableModel::setData()来update一条记录
    model.setData(model.index(row, column), 75000);
    model.submitAll();
    //insert一条记录
    model.insertRows(row, 1);
    model.setData(model.index(row, 0), 1013);
    model.setData(model.index(row, 1), "Peter Gordon");
    model.setData(model.index(row, 2), 68500);
    model.submitAll();
    //delete一条记录
    model.removeRows(row, 5);
    model.submitAll();

    函数QSqlTableModel::submitAll()确保记录写入数据库中。

    QSqlRelationalTableModel 通过外键实现了多表关联。

    //employee表中关联city表、country表。
    model->setTable("employee");
    model->setRelation(2, QSqlRelation("city", "id", "name"));
    model->setRelation(3, QSqlRelation("country", "id", "name"));

    ■、数据呈现视图中

    QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel一般都是借助QListView、QTableView、QTreeView吧数据呈现出来的~
    这里我并不想对QTableView详细讲解,这里不做过多的介绍了,也许会在以后单独QTableView、QTableWidget详细介绍。
    数据库部分是这次的重点!
    继续在对QSqlRelationalTableModel这个作以讲解补充,因为上面提及的实在太少了。

    QSqlRelationalTableModel model;
    model->setTable("employee");
    model->setRelation(2, QSqlRelation("city", "id", "name"));
    model->setRelation(3, QSqlRelation("country", "id", "name"));
    //设置标题头部标签信息
    model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));
    model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));
    model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));
    //值得注意的是,在查询时应该明确指明那个表的数据信息,以下两种方式是等价的。
    model.setFilter(tr("city.name = '%1'").arg("Mucich"));
    //model.setFilter(tr("employee.cityid = %1").arg(312));
    model.select();
    //借助QTableView,把数据信息显示出来,
    QTableView *view = new QTableView;
    view->setModel(model);
    //将表中的项,设计为不能编辑模式
    view->setEditTriggers(QAbstractItemView::NoEditTriggers);
    view->show();

    在将一种通过QSqlField进行Insert、Update、Delete的操作。上边的例子,继续~

    QSqlField idField("id", QVariant::Int);
    QSqlField nameField("name", QVariant::String);
    QSqlField cityIdField("cityId", QVariant::Int);
    QSqlField countryIdField("countryId", QVariant::Int);

    //一条记录 Id = 12、Name = vic.MINg、City = ShenYang、Country = China。(沈阳区号024、中国086)
    idField.setValue(12);
    nameField.setValue("vic.MINg");
    cityIdField.setValue(24);
    countryIdField.setValue(86);

    //insert一条记录,-1表示在最尾端加入
    QSqlRecord record;
    record.append(idField);
    record.append(nameField);
    record.append(cityIdField);
    record.append(countryIdField);
    model->insertRecord(-1, record);

    //update一条记录, row表示要修改的行
    QSqlRecord record = model->record(row);
    record.replace(1, nameField);
    record.replace(2, cityIdField);
    record.replace(3, countryIdField);
    model->setRecord(row, record);

    //delete一条记录, row表示要修改的行
    model->removeRow(row);


    ■、数据呈现窗体中

    通过QDataWidgetMapper可以在窗体控件与数据库中的记录关联在一起。

    QDataWidgetMapper *mapper = new QDataWidgetMapper;
    mapper->setModel(model);
    mapper->addMapping(idSpinBox, 0);
    mapper->addMapping(nameLineEdit, 1);
    mapper->addMapping(cityComboBox, 2);
    mapper->addMapping(countryComboBox, 3);
    //可以通过toFirst()、toNext()、toPrevious()、toLast()、setCurrentIndex()来设置当前记录位置,显示相应数据
    mapper->toFirst();
    //信号、槽的机制model、view、mapper三个联系再一起
    connect(view->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), 
            mapper, SLOT(setCurrentModelIndex(QModelIndex)));

    http://cool.worm.blog.163.com/blog/static/64339006200833024214394/

  • 相关阅读:
    HAProxy、Keepalived 在 Ocatvia 的应用实现与分析
    Octavia 的 HTTPS 与自建、签发 CA 证书
    Octavia 创建 loadbalancer 的实现与分析
    OpenStack Rally 质量评估与自动化测试利器
    自建 CA 中心并签发 CA 证书
    Failed building wheel for netifaces
    通过 vSphere WS API 获取 vCenter Datastore Provisioned Space 置备空间
    OpenStack Placement Project
    我们建了一个 Golang 硬核技术交流群(内含视频福利)
    没有图形界面的软件有什么用?
  • 原文地址:https://www.cnblogs.com/findumars/p/6250739.html
Copyright © 2011-2022 走看看