数据库操作

来源:互联网 发布:军火女王 知乎 编辑:程序博客网 时间:2024/05/21 10:37
  1. qt-win-commercial-src-4.3.1、qt-x11-commercial-src-4.3.1  
  2.   
  3. Microsoft Visual C++ 6.0、KDevelop 3.5.0  
  4.   
  5. Windows Xp、Solaris 10、Fedora 8  
  6.   
  7. SQL Server、Oracle 10g Client  
  8.   
  9.    
  10.   
  11. ■、驱动编译  
  12.   
  13. 这里要提及两个数据库驱动,分别是ODBC和OCI  
  14.   
  15. Windows操作系统中编译ODBC驱动:  
  16.   
  17. 执行以下命令,会在%QTDIR%\plugins\sqldrivers目录下面生成qsqlodbc4.dll。  
  18.   
  19. cd %QTDIR%\src\plugins\sqldrivers\odbc  
  20.   
  21. qmake -o Makefile odbc.pro  
  22.   
  23. nmake  
  24.   
  25. Unix操作系统下编译unixODBC驱动:  
  26.   
  27. unixODBC可以在http://www.unixodbc.org下载。这里假定unixODBC安装在/usr/local/unixODBC。  
  28.   
  29. 执行以下命令,会在$QTDIR/plugins/sqldrivers目录下面生成qsqlodbc4.a。  
  30.   
  31. cd $QTDIR/src/plugins/sqldrivers/odbc  
  32.   
  33. qmake "INCLUDEPATH+=/usr/local/unixODBC/include" "LIBS+=-L/usr/local/unixODBC/lib -lodbc"  
  34.   
  35. make  
  36.   
  37. Windows操作系统中编译OCI驱动:  
  38.   
  39. 这里假定Oracle Client安装在C:\oracle。添加oci.dll动态连接库的环境变量c:\oracle\bin。  
  40.   
  41. set INCLUDE=%INCLUDE%;c:\oracle\oci\include  
  42.   
  43. set LIB=%LIB%;c:\oracle\oci\lib\msvc  
  44.   
  45. cd %QTDIR%\src\plugins\sqldrivers\oci  
  46.   
  47. qmake -o Makefile oci.pro  
  48.   
  49. nmake  
  50.   
  51. Unix操作系统下编译OCI驱动:  
  52.   
  53. 当然根据你的oracle修正下相应的版本号。  
  54.   
  55. cd $QTDIR/src/plugins/sqldrivers/oci  
  56.   
  57. 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  
  58.   
  59. make  
  60.   
  61. 在程序中包含头文件  
  62.   
  63.     #include <QtSql>  
  64.   
  65. 在程序的.pro文件中添加  
  66.   
  67.     QT += sql  
  68.   
  69. ■、数据库连接  
  70.   
  71. 这里则要提及单一数据库连接和多个数据库连接:  
  72.   
  73. 单一数据库连接:  
  74.   
  75. static bool sqlConnection(const QString& HostName,  
  76.   
  77.                                          const QString& DatabaseName,  
  78.   
  79.                                          const QString& UserName,  
  80.   
  81.                                          const QString& Password)  
  82.   
  83. {  
  84.   
  85.     QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");  
  86.   
  87.     db.setHostName(HostName);  
  88.   
  89.     db.setDatabaseName(DatabaseName);  
  90.   
  91.     db.setUserName(UserName);  
  92.   
  93.     db.setPassword(Password);  
  94.   
  95.     if(!db.open())  
  96.   
  97.     {  
  98.   
  99.         QMessageBox::critical(0, QObject::tr("Error"),  
  100.   
  101.                                             QObject::tr("The database reported an error: %1").arg(db.lastError().text()));  
  102.   
  103.         return false;  
  104.   
  105.     }  
  106.   
  107.     //在Qt数据库连接后,运行"SET NAMES 'UTF8'"语句或"SET NAMES 'GBK'"。  
  108.   
  109.     //db.exec("SET NAMES 'UTF8'");  
  110.   
  111.     return true;  
  112.   
  113. }  
  114.   
  115. //多个数据库连接  
  116.   
  117. static bool sqlConnections()  
  118.   
  119. {  
  120.   
  121.     // 创建一个名为odbc的连接  
  122.   
  123.     QSqlDatabase *odbc = QSqlDatabase::addDatabase( "QODBC""ODBC" );  
  124.   
  125.     if ( ! defaultDB ) {  
  126.   
  127.         qWarning( "Failed to connect to odbc driver" );  
  128.   
  129.         return FALSE;  
  130.   
  131.     }  
  132.   
  133.     odbc->setDatabaseName( DB_ODBC_DBNAME );  
  134.   
  135.     odbc->setUserName( DB_ODBC_USER );  
  136.   
  137.     odbc->setPassword( DB_ODBC_PASSWD );  
  138.   
  139.     odbc->setHostName( DB_ODBC_HOST );  
  140.   
  141.     if ( ! odbc->open() ) {  
  142.   
  143.         qWarning( "Failed to open sales database: " + odbc->lastError().driverText() );  
  144.   
  145.         qWarning( odbc->lastError().databaseText() );  
  146.   
  147.         return FALSE;  
  148.   
  149.     }  
  150.   
  151.     // 创建一个名为oracle的连接  
  152.   
  153.     QSqlDatabase *oracle = QSqlDatabase::addDatabase( "QOCI""ORACLE" );  
  154.   
  155.     if ( ! oracle ) {  
  156.   
  157.         qWarning( "Failed to connect to oracle driver" );  
  158.   
  159.         return FALSE;  
  160.   
  161.     }  
  162.   
  163.     oracle->setDatabaseName( DB_ORACLE_DBNAME );  
  164.   
  165.     oracle->setUserName( DB_ORACLE_USER );  
  166.   
  167.     oracle->setPassword( DB_ORACLE_PASSWD );  
  168.   
  169.     oracle->setHostName( DB_ORACLE_HOST );  
  170.   
  171.     if ( ! oracle->open() ) {  
  172.   
  173.         qWarning( "Failed to open orders database: " + oracle->lastError().driverText() );  
  174.   
  175.         qWarning( oracle->lastError().databaseText() );  
  176.   
  177.         return FALSE;  
  178.   
  179.     }  
  180.   
  181.     return TRUE;  
  182.   
  183. }  
  184.   
  185. QSqlDatabase维护着通过addDatabase()这个静态函数返回的的连接指针。  
  186.   
  187. 如果有移去一个连接,先调用QSqlDatabase::close()来关闭连接,然后通过静态函数QSqlDatabase::removeDatabase()来移除连接。  
  188.   
  189. int main(int argc, char *argv[])  
  190.   
  191. {  
  192.   
  193.     QApplication app(argc, argv);  
  194.   
  195.     QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());  
  196.   
  197.     QTextCodec::setCodecForTr(QTextCodec::codecForLocale());  
  198.   
  199.     QFont font("Times", 9, QFont::Normal, FALSE);  
  200.   
  201.     app.setFont(font);  
  202.   
  203.     //连接单一数据库  
  204.   
  205.     if (!sqlConnection("10.0.0.3""qjkzdb""sa""syth7777"))  
  206.   
  207.         return 1;  
  208.   
  209.     //连接多个数据库  
  210.   
  211.     if (!sqlConnections())  
  212.   
  213.         return 1;  
  214.   
  215.     // 数据库被成功打开,得到它们的指针:  
  216.   
  217.     QSqlDatabase *oracledb = QSqlDatabase::database( "ORACLE" );  
  218.   
  219.     // 现在我们可以在oracle连接或默认连接上执行SQL命令  
  220.   
  221.     ...  
  222.   
  223.     return app.exec();  
  224.   
  225. }  
  226.   
  227. ■、SQL执行操作  
  228.   
  229. QSqlQuery提供了对数据库记录的Select、Insert、Update、Delete操作。  
  230.   
  231. SELECT操作:  
  232.   
  233. QSqlQuery query;  
  234.   
  235. query.exec("SELECT name, salary FROM employee WHERE salary > 50000");  
  236.   
  237. while (query.next()) {  
  238.   
  239.     QString name = query.value(0).toString();  
  240.   
  241.     int salary = query.value(1).toInt();  
  242.   
  243.     qDebug() << name << salary;  
  244.   
  245. }  
  246.   
  247. 通过QSqlQuery::next()、QSqlQuery::previous()、QSqlQuery::first()、QSqlQuery::last()、QSqlQuery::seek(),  
  248.   
  249. 可以得到下一条、上一条、第一条、最后一条、任意一条记录的位置。  
  250.   
  251. INSERT操作:  
  252.   
  253. //单一插入数据  
  254.   
  255. QSqlQuery query;  
  256.   
  257. query.prepare("INSERT INTO employee (id, name, salary) "  
  258.   
  259.                         "VALUES (:id, :name, :salary)");  
  260.   
  261. query.bindValue(":id", 1001);  
  262.   
  263. query.bindValue(":name""Thad Beaumont");  
  264.   
  265. query.bindValue(":salary", 65000);  
  266.   
  267. query.exec();  
  268.   
  269. //批量插入数据  
  270.   
  271. QSqlQuery query;  
  272.   
  273. query.prepare("insert into myTable values (?, ?)");  
  274.   
  275. QVariantList ints;  
  276.   
  277. ints << 1 << 2 << 3 << 4;  
  278.   
  279. query.addBindValue(ints);  
  280.   
  281. QVariantList names;  
  282.   
  283. names << "Harald" << "Boris" << "Trond" << QVariant(QVariant::String);  
  284.   
  285. query.addBindValue(names);  
  286.   
  287. if (!query.execBatch())  
  288.   
  289.     qDebug() << query.lastError();  
  290.   
  291. UPDATE操作:  
  292.   
  293. QSqlQuery query;  
  294.   
  295. query.prepare("UPDATE employee SET salary = ? WHERE id = 1003");  
  296.   
  297. query.bindValue(0, 70000);  
  298.   
  299. query.exe();  
  300.   
  301. DELETE操作:  
  302.   
  303. QSqlQuery query;  
  304.   
  305. query.exec("DELETE FROM employee WHERE id = 1007");  
  306.   
  307. 事务处理:  
  308.   
  309. QSqlDatabase::database().transaction();  
  310.   
  311. QSqlQuery query;  
  312.   
  313. query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");  
  314.   
  315. if (query.next()) {  
  316.   
  317.     int employeeId = query.value(0).toInt();  
  318.   
  319.     query.exec("INSERT INTO project (id, name, ownerid) "  
  320.   
  321.                        "VALUES (201, 'Manhattan Project', "  
  322.   
  323.                        + QString::number(employeeId) + ")");  
  324.   
  325. }  
  326.   
  327. QSqlDatabase::database().commit();  
  328.   
  329. 如果数据库引擎支持事务处理,则函数QSqlDriver::hasFeature(QSqlDriver::Transactions)将返回 真。  
  330.   
  331. 可以通过调用QSqlDatabase::transaction()来初始化一个事务处理。之后执行你想在该事务处理的工作。  
  332.   
  333. 完了再执行QSqlDatabase::commit()来提交事务处理或QSqlDatabase::rollback()取消事务处理。  
  334.   
  335. 这里在举个QSqlDriver::hasFeature(QSqlDriver::QuerySize)例子,可以较快的统计查询记录行数。  
  336.   
  337. QSqlQuery query;  
  338.   
  339. int numRows;  
  340.   
  341. query.exec("SELECT name, salary FROM employee WHERE salary > 50000");  
  342.   
  343. QSqlDatabase defaultDB = QSqlDatabase::database();  
  344.   
  345. if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {  
  346.   
  347.     numRows = query.size();  
  348.   
  349. else {  
  350.   
  351.      // this can be very slow  
  352.   
  353.      query.last();  
  354.   
  355.      numRows = query.at() + 1;  
  356.   
  357. }  
  358.   
  359. 存储过程:  
  360.   
  361. AsciiToInt()是数据库中的一个存储过程。  
  362.   
  363. 但我在网上以前好像看过说是SQL Server中的存储过程是通过"EXEC"完成的,而不是"CALL",这里我不确定!留下一个疑问吧~  
  364.   
  365. QSqlQuery query;  
  366.   
  367. query.prepare("CALL AsciiToInt(?, ?)");  
  368.   
  369. query.bindValue(0, "A");  
  370.   
  371. query.bindValue(1, 0, QSql::Out);  
  372.   
  373. query.exec();  
  374.   
  375. int i = query.boundValue(1).toInt(); // i is 65  
  376.   
  377. ■、使用SQL Model类  
  378.   
  379. QSqlQueryModel:一个只读的读取数据库数据的模型。  
  380.   
  381. QSqlTableModel:一个可读写的单一表格模型,可以不用写SQL语句。  
  382.   
  383. QSqlRelationalTableModel:QSqlTableModel的一个子类,可多表关联在一起。  
  384.   
  385. 这些类都继承于QAbstractTableModel,而它们又都继承于QAbstractItemModel。  
  386.   
  387. QSqlQueryModel 只读模式,基于SQL查询基础。  
  388.   
  389. QSqlQueryModel model;  
  390.   
  391. model.setQuery("SELECT * FROM employee");  
  392.   
  393. for (int i = 0; i < model.rowCount(); ++i) {  
  394.   
  395.     int id = model.record(i).value("id").toInt();  
  396.   
  397.     QString name = model.record(i).value("name").toString();  
  398.   
  399.     qDebug() << id << name;  
  400.   
  401. }  
  402.   
  403. QSqlTableModel 可对单一表操作,进行读写操作。  
  404.   
  405. //读取数据  
  406.   
  407. QSqlTableModel model;  
  408.   
  409. model.setTable("employee");  
  410.   
  411. model.setFilter("salary > 50000");  
  412.   
  413. model.setSort(2, Qt::DescendingOrder);  
  414.   
  415. model.select();  
  416.   
  417. for (int i = 0; i < model.rowCount(); ++i) {  
  418.   
  419.     QString name = model.record(i).value("name").toString();  
  420.   
  421.     int salary = model.record(i).value("salary").toInt();  
  422.   
  423.     qDebug() << name << salary;  
  424.   
  425. }  
  426.   
  427. //通过QSqlTableModel::setRecord()修改数据  
  428.   
  429. for (int i = 0; i < model.rowCount(); ++i) {  
  430.   
  431.     QSqlRecord record = model.record(i);  
  432.   
  433.     double salary = record.value("salary").toInt();  
  434.   
  435.     salary *= 1.1;  
  436.   
  437.     record.setValue("salary", salary);  
  438.   
  439.     model.setRecord(i, record);  
  440.   
  441. }  
  442.   
  443. model.submitAll();  
  444.   
  445. //通过QSqlTableModel::setData()来update一条记录  
  446.   
  447. model.setData(model.index(row, column), 75000);  
  448.   
  449. model.submitAll();  
  450.   
  451. //insert一条记录  
  452.   
  453. model.insertRows(row, 1);  
  454.   
  455. model.setData(model.index(row, 0), 1013);  
  456.   
  457. model.setData(model.index(row, 1), "Peter Gordon");  
  458.   
  459. model.setData(model.index(row, 2), 68500);  
  460.   
  461. model.submitAll();  
  462.   
  463. //delete一条记录  
  464.   
  465. model.removeRows(row, 5);  
  466.   
  467. model.submitAll();  
  468.   
  469. 函数QSqlTableModel::submitAll()确保记录写入数据库中。  
  470.   
  471. QSqlRelationalTableModel 通过外键实现了多表关联。  
  472.   
  473. //employee表中关联city表、country表。  
  474.   
  475. model->setTable("employee");  
  476.   
  477. model->setRelation(2, QSqlRelation("city""id""name"));  
  478.   
  479. model->setRelation(3, QSqlRelation("country""id""name"));  
  480.   
  481.    
  482.   
  483. ■、数据呈现视图中  
  484.   
  485. QSqlQueryModel、QSqlTableModel、QSqlRelationalTableModel一般都是借助QListView、QTableView、QTreeView吧数据呈现出来的~  
  486.   
  487. 这里我并不想对QTableView详细讲解,这里不做过多的介绍了,也许会在以后单独QTableView、QTableWidget详细介绍。  
  488.   
  489. 数据库部分是这次的重点!  
  490.   
  491. 继续在对QSqlRelationalTableModel这个作以讲解补充,因为上面提及的实在太少了。  
  492.   
  493. QSqlRelationalTableModel model;  
  494.   
  495. model->setTable("employee");  
  496.   
  497. model->setRelation(2, QSqlRelation("city""id""name"));  
  498.   
  499. model->setRelation(3, QSqlRelation("country""id""name"));  
  500.   
  501. //设置标题头部标签信息  
  502.   
  503. model->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));  
  504.   
  505. model->setHeaderData(1, Qt::Horizontal, QObject::tr("Name"));  
  506.   
  507. model->setHeaderData(2, Qt::Horizontal, QObject::tr("City"));  
  508.   
  509. model->setHeaderData(3, Qt::Horizontal, QObject::tr("Country"));  
  510.   
  511. //值得注意的是,在查询时应该明确指明那个表的数据信息,以下两种方式是等价的。  
  512.   
  513. model.setFilter(tr("city.name = '%1'").arg("Mucich"));  
  514.   
  515. //model.setFilter(tr("employee.cityid = %1").arg(312));  
  516.   
  517. model.select();  
  518.   
  519. //借助QTableView,把数据信息显示出来,  
  520.   
  521. QTableView *view = new QTableView;  
  522.   
  523. view->setModel(model);  
  524.   
  525. //将表中的项,设计为不能编辑模式  
  526.   
  527. view->setEditTriggers(QAbstractItemView::NoEditTriggers);  
  528.   
  529. view->show();  
  530.   
  531. 在将一种通过QSqlField进行Insert、Update、Delete的操作。上边的例子,继续~  
  532.   
  533. QSqlField idField("id", QVariant::Int);  
  534.   
  535. QSqlField nameField("name", QVariant::String);  
  536.   
  537. QSqlField cityIdField("cityId", QVariant::Int);  
  538.   
  539. QSqlField countryIdField("countryId", QVariant::Int);  
  540.   
  541. //一条记录 Id = 12、Name = vic.MINg、City = ShenYang、Country = China。(沈阳区号024、中国086)  
  542.   
  543. idField.setValue(12);  
  544.   
  545. nameField.setValue("vic.MINg");  
  546.   
  547. cityIdField.setValue(24);  
  548.   
  549. countryIdField.setValue(86);  
  550.   
  551. //insert一条记录,-1表示在最尾端加入  
  552.   
  553. QSqlRecord record;  
  554.   
  555. record.append(idField);  
  556.   
  557. record.append(nameField);  
  558.   
  559. record.append(cityIdField);  
  560.   
  561. record.append(countryIdField);  
  562.   
  563. model->insertRecord(-1, record);  
  564.   
  565. //update一条记录, row表示要修改的行  
  566.   
  567. QSqlRecord record = model->record(row);  
  568.   
  569. record.replace(1, nameField);  
  570.   
  571. record.replace(2, cityIdField);  
  572.   
  573. record.replace(3, countryIdField);  
  574.   
  575. model->setRecord(row, record);  
  576.   
  577. //delete一条记录, row表示要修改的行  
  578.   
  579. model->removeRow(row);  
  580.   
  581. ■、数据呈现窗体中  
  582.   
  583. 通过QDataWidgetMapper可以在窗体控件与数据库中的记录关联在一起。  
  584.   
  585. QDataWidgetMapper *mapper = new QDataWidgetMapper;  
  586.   
  587. mapper->setModel(model);  
  588.   
  589. mapper->addMapping(idSpinBox, 0);  
  590.   
  591. mapper->addMapping(nameLineEdit, 1);  
  592.   
  593. mapper->addMapping(cityComboBox, 2);  
  594.   
  595. mapper->addMapping(countryComboBox, 3);  
  596.   
  597. //可以通过toFirst()、toNext()、toPrevious()、toLast()、setCurrentIndex()来设置当前记录位置,显示相应数据  
  598.   
  599. mapper->toFirst();  
  600.   
  601. //信号、槽的机制model、view、mapper三个联系再一起  
  602.   
  603. connect(view->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),  
  604.   
  605.         mapper, SLOT(setCurrentModelIndex(QModelIndex)));  
0 0
原创粉丝点击