很多時(shí)候,我們需要將大量數(shù)據(jù)從一個(gè)系統(tǒng)導(dǎo)入到另一個(gè)系統(tǒng)中。比如我們經(jīng)常聽到的 ERP 系統(tǒng)數(shù)據(jù)同步,就需要將業(yè)務(wù)數(shù)據(jù)從一個(gè) ERP 系統(tǒng)導(dǎo)入到另一個(gè) ERP 系統(tǒng)中。而對(duì)于 Oracle 數(shù)據(jù)庫來說,我們可以使用 C 語言編寫的程序來實(shí)現(xiàn)批量導(dǎo)入數(shù)據(jù)。
首先我們來看一個(gè)簡單的例子,假設(shè)我們有一個(gè)文本文件 data.txt,里面存放著 100 條數(shù)據(jù),每條數(shù)據(jù)包括 id 和 name 兩個(gè)字段,用逗號(hào)分隔。我們要將這些數(shù)據(jù)導(dǎo)入到一個(gè) Oracle 數(shù)據(jù)庫表 data_table 中:
10,Tom
20,Jack
30,Lucy
......
我們可以使用以下代碼來實(shí)現(xiàn):
#include <stdio.h>
#include <string.h>
#include <oci.h>
#define BUF_SIZE 256
int main()
{
OCIEnv *env;
OCIServer *srv;
OCIError *err;
OCISession *ses;
OCITrans *trans;
OCIStmt *stmt;
OCIBind *bind1, *bind2;
char *username = "user";
char *password = "password";
char *db = "orcl";
char *sql = "INSERT INTO data_table(id, name) VALUES (:id, :name)";
int id, len;
char *name;
FILE *fp;
char buf[BUF_SIZE];
env = NULL;
srv = NULL;
err = NULL;
ses = NULL;
trans = NULL;
stmt = NULL;
bind1 = NULL;
bind2 = NULL;
OCIInitialize(OCI_OBJECT, NULL, NULL, NULL, NULL);
OCIEnvInit(&env, OCI_DEFAULT, 0, NULL);
OCIHandleAlloc(env, (void **)&srv, OCI_HTYPE_SERVER, 0, NULL);
OCIHandleAlloc(env, (void **)&err, OCI_HTYPE_ERROR, 0, NULL);
OCIHandleAlloc(env, (void **)&ses, OCI_HTYPE_SESSION, 0, NULL);
OCIHandleAlloc(env, (void **)&trans, OCI_HTYPE_TRANS, 0, NULL);
OCIHandleAlloc(env, (void **)&stmt, OCI_HTYPE_STMT, 0, NULL);
OCIServerAttach(srv, err, (unsigned char *)db, strlen(db), OCI_DEFAULT);
OCIAttrSet(ses, OCI_HTYPE_SESSION, (void *)username, strlen(username), OCI_ATTR_USERNAME, err);
OCIAttrSet(ses, OCI_HTYPE_SESSION, (void *)password, strlen(password), OCI_ATTR_PASSWORD, err);
OCISessionBegin(srv, err, ses, OCI_CRED_RDBMS, OCI_DEFAULT);
OCIAttrSet(stmt, OCI_HTYPE_STMT, (void *)trans, sizeof(OCITrans *), OCI_ATTR_TRANS, err);
OCIStmtPrepare(stmt, err, (unsigned char *)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
OCIDefineByPos(stmt, &bind1, err, 1, &id, sizeof(id), SQLT_INT, NULL, NULL, NULL, OCI_DEFAULT);
OCIDefineByPos(stmt, &bind2, err, 2, NULL, 0, SQLT_STR, NULL, NULL, NULL, OCI_DEFAULT);
OCIStmtExecute(ses, stmt, trans, 1, 0, NULL, NULL, OCI_COMMIT_ON_SUCCESS);
fp = fopen("data.txt", "r");
while(fgets(buf, BUF_SIZE, fp))
{
len = strlen(buf);
name = (char *)malloc(len);
sscanf(buf, "%d,%s", &id, name);
OCIStmtBindByPos(stmt, &bind1, err, 1, &id, sizeof(id), SQLT_INT, NULL);
OCIStmtBindByPos(stmt, &bind2, err, 2, name, strlen(name), SQLT_STR, NULL);
OCIStmtExecute(ses, stmt, trans, 1, 0, NULL, NULL, OCI_COMMIT_ON_SUCCESS);
}
fclose(fp);
OCIHandleFree(srv, OCI_HTYPE_SERVER);
OCIHandleFree(err, OCI_HTYPE_ERROR);
OCIHandleFree(ses, OCI_HTYPE_SESSION);
OCIHandleFree(trans, OCI_HTYPE_TRANS);
OCIHandleFree(stmt, OCI_HTYPE_STMT);
OCIHandleFree(env, OCI_HTYPE_ENV);
return 0;
}
上面的代碼中,我們首先定義了一些 Oracle 相關(guān)的數(shù)據(jù)結(jié)構(gòu),比如 OCIEnv、OCIServer、OCIError、OCISession、OCITrans、OCIStmt 等等。然后我們使用 OCIInitialize 和 OCIEnvInit 函數(shù)來初始化 OCI 環(huán)境。接著,我們使用 OCIHandleAlloc 函數(shù)來分配空間,創(chuàng)建對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)對(duì)象。我們將數(shù)據(jù)庫連接信息、用戶信息、事務(wù)信息、SQL 語句等等都傳遞給相應(yīng)的對(duì)象。之后我們使用 OCIDefineByPos 函數(shù)來設(shè)置 OCIBind 對(duì)象,在本例中我們要綁定兩個(gè)參數(shù) id 和 name。然后我們使用 OCIStmtExecute 函數(shù)來執(zhí)行 SQL 語句。
最后,我們使用 fopen 和 fgets 函數(shù)來讀取文件數(shù)據(jù),使用 sscanf 函數(shù)來解析數(shù)據(jù)。我們使用 OCIStmtBindByPos 函數(shù)來綁定數(shù)據(jù),再次使用 OCIStmtExecute 函數(shù)來執(zhí)行 SQL 語句。注意:我們需要在循環(huán)內(nèi)部執(zhí)行 SQL 語句,以保證每批次數(shù)據(jù)都能成功入庫。