程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SyBase數據庫 >> SyBase綜合文章 >> Sybase批量操作(BCP)的設計和實現

Sybase批量操作(BCP)的設計和實現

編輯:SyBase綜合文章

本文主要講述了Sybase數據庫批量操作(BCP)的設計和實現,以及在開發過程中的關鍵點,為後續開發者提供了技術基礎 一、前言

在項目研發過程中,需要開發一個數據庫批量操作的動態鏈接庫(DLL),以前的實現主要是程序中直接調用bcp.exe,這種方式由應用程序創建子進程,不好控制批量操作過程,失敗跟蹤難度比較大,因此想利用bcp.exe調用的函數來實現操作過程。本人通過分析bcp.exe程序,得到了批量操作的DB LIBRARY API函數,再查閱API函數的資料得以實現該動態鏈接庫。

二、實現

批量操作動態鏈接庫只實現了一個輸出函數, 應用程序通過動態加載DLL,再獲取函數地址,便可調用函數實現批量操作。

輸出函數定義如下:LIBBCP_API BOOL BCP_Transfer_2(const char *task, const char *step, const char *config, long *copIEdrow);

在動態鏈接庫中定義了兩個類:CInteriorGlobal和CSYBBCP。CInteriorGlobal完成全局的初始化操作,CSYBBCP實現數據庫的批量操作。 在調用Sybase數據庫的DB LIBRARY API函數進行數據庫的相關操作時,首先需要調用dbsetversion函數設置版本信息,這個函數只能調用一次,如果再次調用則會報錯。而類CSYBBCP在BCP_Transfer_2函數中動態創建和釋放,如果在CSYBBCP中直接調用dbsetversion會導致多次調用出錯。因此需要采用一種機制讓dbsetversion只能調用一次,這裡使用了設計模式中的SingleTom模式,SingleTom模式就是確保實例唯一,本人利用該類僅做一次實例化操作來初始化Sybase客戶端版本信息。

下面是CInteriorGlobal的定義:

class CInteriorGlobal

{

public:

static CInteriorGlobal *Instance();

private:

CInteriorGlobal();

private:

static CInteriorGlobal *_instance;

};

CInteriorGlobal的實現,在構造函數中設置版本信息:CInteriorGlobal::CInteriorGlobal()

{

dbsetversion(DBVERSION_100);

}

CInteriorGlobal *CInteriorGlobal::_instance = 0;

CInteriorGlobal * CInteriorGlobal::Instance()

{

if(0 == _instance)

_instance = new CInteriorGlobal;

return _instance;

}

為了完成批量操作,定義類CSYBBCP,具體定義如下:class CSYBBCP

{

public:

CSYBBCP();

~CSYBBCP();

BOOL DoConnect(int taskindex, int stepindex, char *server, char *database, char *username,

char *passWord, char *charset, char *language);

BOOL DoQuery(char *sql, char **buf, int *rowcount, int *fIEldcount);

BOOL DoUpdate(char *sql, char *database = NULL);

BOOL BCP_Connect(int taskindex, int stepindex, char *server, char *database,

char *username, char *passWord, char *charset, char *language);

BOOL BCP_Transfer_db(char *sql, char *fldterminator, char *rowterminator, int direction,

char *datafile, char *errfile, long *copIEdrow);

private:

BOOL m_isbcpout;

int m_stepindex;

int m_taskindex;

char m_vIEwname[MAX_STRING_NUM];

char m_database[MAX_STRING_NUM];

DBPROCESS *m_dbproc;

private:

int GetTableFIEldNums(char *table);

BOOL DoDisconnect();

};

在類CSYBBCP中,主要是函數BCP_Transfer_db進行數據庫大批量數據的導入和導出,要完成數據傳輸操作,需要如下幾個步驟: // 初始化:指定表明和數據文件

if(bcp_init(m_dbproc, tablename, datafile, NULL, direction) == FAIL)

{

return FALSE;

}

// 設置批量操作的控制參數,這裡設置的每批記錄數

if(bcp_control(m_dbproc, BCPBATCH, (DBINT) 1000) == FAIL)

{

return FALSE;

}

// 設置列數

if(bcp_columns(m_dbproc, cCols) == FAIL)

{

return FALSE;

}

// 設置列格式

for(ii = 1; ii < cCols; ii++)
{
if(bcp_colfmt(m_dbproc, ii, SYBCHAR, 0, -1, (UINT8 *) fldterminator, _strlen(fldterminator), ii) == FAIL)
{
return FALSE;
}
}
if(bcp_colfmt(m_dbproc, ii, SYBCHAR, 0, -1, (UINT8 *) rowterminator, _strlen(rowterminator), ii) == FAIL)
{
return FALSE;
}
// 執行批量操作
while(bcp_exec(m_dbproc, & cRows) == FAIL)
{
return FALSE;
}

// 批量操作結束

retcode=bcp_done(m_dbproc);

在使用Sybase12.5客戶端之前,程序未調用bcp_control函數,在執行bcp_exec函數時不是使用while,而是使用if判斷,代碼如下:

if(bcp_exec(m_dbproc, & cRows) == FAIL)
{
    return FALSE;
}

程序能正常完成功能,當使用Sybase12.5客戶端後,在執行時發現程序突然退出,異常處理也未能記錄日志,後跟蹤發現程序是在執行bcp_exec時退出,但是未能查出原因,咨詢Sybase公司技術人員,也沒能解決問題。後來在一次測試中偶然發現有時能導入數據,於是測試數據文件在什麼情況下能導入,實驗其臨界點,多次測試後發現文件1000條記錄為臨界點,超過則出現問題。於是本人在程序中調用bcp_control函數,設置批量記錄為1000,如果數據文件記錄多於1000,則需要bcp_exec執行多次才能完成,所以采用while,而不是if,這樣問題解決。 三、結束

在上面的論述中,還僅僅涉及DB LIBRARY,對於Sybase客戶端編程,還有CT LIBRARY方式,目前CT已經支持導出,但不支持導入。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved