1. 程式人生 > >VC++實現批量大容量快速插入SqlServer資料庫

VC++實現批量大容量快速插入SqlServer資料庫

1. 概述

使用c++訪問資料庫的方法很多,由於我訪問的是sqlserver資料庫,於是上MSDN查了一下有哪些訪問技術,主要有以下幾種:
  • ODBC  
  • OLEDB
  • ADO
ADO是OLEDB的封裝,使用起來比OLEDB方便。由於ADO比OLEDB多了一層,其速度可能不及OLEDB,所以就不考慮ADO了。 ODBC訪問sqlserver有一個好處,可以在linux上使用。linux上可以使用FreeTDS作為sqlserver的ODBC驅動。OLEDB則只能在windows上執行。

1.1 ODBC(Open Database Connectivity)

ODBC是微軟弄出來的一個可以訪問各種資料庫的介面。ODBC存在時間比較長,是一個比較穩定的介面。它既然能夠訪問各種介面,所以它是一個最小公共集的介面。這個接口裡面可能會缺少某些資料庫的特定功能。 ODBC只是一個介面,想要使用ODBC必須提供驅動。 sqlserver 提供SQL Server Native Client ODBC driver來支援ODBC介面。

1.2 OLEDB

OLEDB是一組基於COM的介面。OLEDB提供統一的介面,訪問各種形式的資料。說到OLEDB就必須提交兩個概念:consumer(使用介面的程式)、provider(介面的實現者)。OLEDB是定義一組介面,每個資料庫供應商如果要是自己的資料庫能通過OLEDB訪問,就必須提供OLEDB Provider。 sqlserver的的provider是The SQL Server Native Client OLE DB provider。

2. 使用ODBC插入資料

ODBC插入資料速度快捷的方法主要有兩種: 1. SQLBulkOperations 
  1. #include <windows.h>
  2. #include <sqlext.h>
  3. #include <stdio.h>
  4. #include <time.h>
  5. SQLHENV henv = NULL;  
  6. SQLHDBC hdbc = NULL;  
  7. SQLHSTMT hstmt = NULL;  
  8. SQLRETURN retcode;  
  9. #define COUNT  (100000)
  10. #define ROW_ARRAY_SIZE 1000
  11. typedefstruct{  
  12.     SQLINTEGER rec_num;  
  13.     SQLINTEGER rec_numInd;  
  14.     SQLCHAR date[9];  
  15.     SQLINTEGER dateInd;  
  16.     SQLCHAR time[9];  
  17.     SQLINTEGER timeInd;  
  18.     SQLCHAR reff[11];  
  19.     SQLINTEGER reffInd;  
  20.     SQLCHAR acc[11];  
  21.     SQLINTEGER accInd;  
  22.     SQLCHAR stock[7];  
  23.     SQLINTEGER stockInd;  
  24.     SQLCHAR bs[2];  
  25.     SQLINTEGER bsInd;  
  26.     SQLCHAR price[9];  
  27.     SQLINTEGER priceInd;  
  28.     SQLCHAR qty[9];  
  29.     SQLINTEGER qtyInd;  
  30.     SQLCHAR status[2];  
  31.     SQLINTEGER statusInd;  
  32.     SQLCHAR owflag[4];  
  33.     SQLINTEGER owflagInd;  
  34.     SQLCHAR ordrec[9];  
  35.     SQLINTEGER ordrecInd;  
  36.     SQLCHAR firmid[6];  
  37.     SQLINTEGER firmidInd;  
  38.     SQLCHAR branchid[6];  
  39.     SQLINTEGER branchidInd;  
  40.     SQLSCHAR checkord[16];  
  41.     SQLINTEGER checkordInd;  
  42. } ORDWTH;  
  43. typedefstruct{  
  44.     SQLINTEGER id;  
  45.     SQLCHAR date[20];  
  46.     SQLCHAR abbr[10];  
  47. //
  48.     SQLINTEGER idInd;  
  49.     SQLINTEGER dateInd;  
  50.     SQLINTEGER abbrInd;  
  51. } Test;  
  52. Test test_array[ROW_ARRAY_SIZE];  
  53. ORDWTH  ordwth_array[ROW_ARRAY_SIZE];  
  54. int rec_num = 1;  
  55. void main()  
  56. {  
  57.     retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  58.     retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);  
  59.     retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);  
  60.     retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  61.     retcode = SQLConnect(hdbc, (SQLCHAR*) "ctp2_lx", SQL_NTS, (SQLCHAR*)"sa", SQL_NTS, (SQLCHAR*)"123456", SQL_NTS);  
  62.     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)  
  63.     {  
  64.     }  
  65.     else
  66.     {  
  67.         SQLCHAR msg[128];  
  68.         SQLCHAR state[128];  
  69.         SQLINTEGER error_id;  
  70.         SQLSMALLINT text;  
  71.         SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state, &error_id, msg, 128, &text);  
  72.         printf("db connect fail, sqlstate=%s, errormsg=%s\n", state, msg);  
  73.         system("pause");  
  74.         return;  
  75.     }  
  76.     retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  77.     printf("Inserting...\n");  
  78.     time_t begin;  
  79.     time(&begin);  
  80.     //設定SQL_ATTR_ROW_ARRAY_SIZE屬性,bulk的長度
  81.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE, 0);  
  82.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), 0);  
  83.     SQLUSMALLINT ParamStatusArray[ROW_ARRAY_SIZE] = { 0 };  
  84.     //設定狀態陣列
  85.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, ParamStatusArray, 0);  
  86.     SQLINTEGER nBindOffset = 0;  
  87.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER)&nBindOffset, 0);  
  88.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);  
  89.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);  
  90.     //進行一次查詢,得到result set
  91.     retcode = SQLExecDirect(hstmt, (SQLCHAR*)"select rec_num, date, time, reff, acc, stock, bs, price, qty, status, owflag, ordrec, firmid, branchid, checkord  from ashare_ordwth", SQL_NTS);  
  92.     //retcode = SQLExecDirect(hstmt, (SQLCHAR*)"select id, date, abbr from test", SQL_NTS);
  93.     retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
  94.     /*SQLBindCol(hstmt, 1, SQL_C_SHORT, &test_array[0].id, 0, &test_array[0].idInd); 
  95.     SQLBindCol(hstmt, 2, SQL_C_CHAR, &test_array[0].date, 20, &test_array[0].dateInd); 
  96.     SQLBindCol(hstmt, 3, SQL_C_CHAR, &test_array[0].abbr, 10, &test_array[0].abbrInd);*/
  97.     retcode = SQLBindCol(hstmt, 1, SQL_C_LONG, &ordwth_array[0].rec_num, 0, &ordwth_array[0].rec_numInd);  
  98.     SQLBindCol(hstmt, 2, SQL_C_CHAR, &ordwth_array[0].date, sizeof(ordwth_array[0].date), &ordwth_array[0].dateInd);  
  99.     SQLBindCol(hstmt, 3, SQL_C_CHAR, &ordwth_array[0].time, sizeof(ordwth_array[0].time), &ordwth_array[0].timeInd);  
  100.     SQLBindCol(hstmt, 4, SQL_C_CHAR, &ordwth_array[0].reff, sizeof(ordwth_array[0].reff), &ordwth_array[0].reffInd);  
  101.     SQLBindCol(hstmt, 5, SQL_C_CHAR, &ordwth_array[0].acc, sizeof(ordwth_array[0].acc), &ordwth_array[0].accInd);  
  102.     SQLBindCol(hstmt, 6, SQL_C_CHAR, &ordwth_array[0].stock, sizeof(ordwth_array[0].stock), &ordwth_array[0].stockInd);  
  103.     SQLBindCol(hstmt, 7, SQL_C_CHAR, &ordwth_array[0].bs, sizeof(ordwth_array[0].bs), &ordwth_array[0].bsInd);  
  104.     SQLBindCol(hstmt, 8, SQL_C_CHAR, &ordwth_array[0].price, sizeof(ordwth_array[0].price), &ordwth_array[0].priceInd);  
  105.     SQLBindCol(hstmt, 9, SQL_C_CHAR, &ordwth_array[0].qty, sizeof(ordwth_array[0].qty), &ordwth_array[0].qtyInd);  
  106.     SQLBindCol(hstmt, 10, SQL_C_CHAR, &ordwth_array[0].status, sizeof(ordwth_array[0].status), &ordwth_array[0].statusInd);  
  107.     SQLBindCol(hstmt, 11, SQL_C_CHAR, &ordwth_array[0].owflag, sizeof(ordwth_array[0].owflag), &ordwth_array[0].owflagInd);  
  108.     SQLBindCol(hstmt, 12, SQL_C_CHAR, &ordwth_array[0].ordrec, sizeof(ordwth_array[0].ordrec), &ordwth_array[0].ordrecInd);  
  109.     SQLBindCol(hstmt, 13, SQL_C_CHAR, &ordwth_array[0].firmid, sizeof(ordwth_array[0].firmid), &ordwth_array[0].firmidInd);  
  110.     SQLBindCol(hstmt, 14, SQL_C_CHAR, &ordwth_array[0].branchid, sizeof(ordwth_array[0].branchid), &ordwth_array[0].branchidInd);  
  111.     SQLBindCol(hstmt, 15, SQL_C_BINARY, &ordwth_array[0].checkord, sizeof(ordwth_array[0].checkord), &ordwth_array[0].checkordInd);  
  112.     //關閉auto commit
  113.     SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);  
  114.     for (int j = 0; j < COUNT / ROW_ARRAY_SIZE; j++)  
  115.     {  
  116.         for (int i = 0; i < ROW_ARRAY_SIZE; i++)  
  117.         {  
  118.             ordwth_array[i].rec_num = rec_num++;  
  119.             ordwth_array[i].ordrecInd = 0;  
  120.             strcpy((char*)ordwth_array[i].date, "20150120");  
  121.             ordwth_array[i].dateInd = SQL_NTS;  
  122.             strcpy((char*)ordwth_array[i].time, "13:20:10");  
  123.             ordwth_array[i].timeInd = SQL_NTS;  
  124.             strcpy((char*)ordwth_array[i].reff, "1234567890"