我最近才開始學習oci,看到有關多線程的部分時對于多線程情況下的mode參數設置有些疑問.
1.在 Oracle Call Interface PRogrammer's Guide 中這樣寫"In order to take advantage of thread safety, an application must be running on a thread-safe platform. Then the application must tell the OCI layer that theapplication is running in multithreaded mode, by specifying OCI_THREADED for the mode parameter of the opening call to OCIEnvCreate()."也就是說在多線程的程序中需要用OCI_THREADED.
2.而在oci本身自帶的Multi-threading example中卻是用OCI_DEFAULT
調用的OCIEnvCreate().
3.在文檔中關于environment的mutex保護又有這樣一段話
"The following three scenarios are possible, depending on how many connections exist in each environment handle, and how many threads will be spawned in each connection
1.If an application has multiple environment handles, but each only has one thread (one session exists in each environment handle), no mutexing is required.
2.If an application running in OCI_THREADED mode maintains one or more environment handles, each of which has multiple connections, it also has the following options:
Pass a value of OCI_NO_MUTEX for the mode of OCIEnvCreate(). In this case the application must mutex OCI calls by made on the same environment handle itself. This has the advantage that the mutexing scheme can be optimized based on the application design. The programmer must also insure that only one OCI call is in process on the environment handle connection at any given time.
Pass a value of OCI_DEFAULT to OCIEnvCreate(). In this case, the OCI library automatically gets a mutex on every OCI call on the same environment handle."
結合 2,3小第猜想假如在多線程的情況下假如每個env只包含一個數據庫的連接,則不需要使用OCI_THREADED 來調用OCIEnvCreate().假如每個env包含多于一個的數據庫連接則需要OCI_THREADED.
因為我剛開始看oci的東西,所以還沒有寫過半程序來測試,希望有相關經驗的大俠拔刀相助.
希望感愛好的人一起研究一下.要試這個問題首先要寫連接程序,我用c++寫了簡單的連接類現在已經調試通過了,寫的匆忙沒有什么錯誤控制代碼.貼出來給大家討論,因為我是第一次寫所以肯定有不少問題,現在也是沒有辦法啊.希望大俠出現啊.
h file
#ifndef __ORACONNECT_H__
#define __ORACONNECT_H__
#include
extern "C"
{
sWord OCIEnvCreate (OCIEnv **envp, ub4 mode, dvoid *ctXP,
dvoid *(*malocfp)(dvoid *ctxp, size_t size),
dvoid *(*ralocfp)(dvoid *ctxp, dvoid *memptr, size_t newsize),
void (*mfreefp)(dvoid *ctxp, dvoid *memptr),
size_t xtramem_sz, dvoid **usrmempp);
}
class OraConnect
{
public:
OraConnect();
~OraConnect();
bool Connect();
bool DisConnect();
void setUsername(char* strusername);
void setPassword(char* strpassword);
void setDbname(char* strdbname);
void checkerr(OCIError *errhp,sword status);
protected:
private:
char username[128];
char password[128];
char dbname[128];
//Set the OCI variable
OCIEnv *envhp;
OCIError *errhp;
OCISession *authp;
OCIServer *srvhp;
OCISvcCtx *svchp;
};
#endif
.cpp file
#include "StdAfx.h"
#include "Connect.h"
OraConnect::OraConnect()
{
}
OraConnect::~OraConnect()
{
}
void
OraConnect::setUsername(char* strusername)
{
strcpy(username,strusername);
}
void
OraConnect::setPassword(char* strpassword)
{
strcpy(password,strpassword);
}
void
OraConnect::setDbname(char* strdbname)
{
strcpy(dbname,strdbname);
}
bool
OraConnect::Connect()
{
ub4 mode = OCI_SHAREDOCI_THREADED;
//ub4 mode=OCI_DEFAULT;
//Create the envirnment.
//(void) OCIEnvCreate(&envhp, mode, (CONST dvoid *)0, 0, 0, 0, (size_t)0, (dvoid **)0);
(void) OCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0,(dvoid * (*)(dvoid *, size_t)) 0,(dvoid * (*)(dvoid *, dvoid *, size_t))0,(void (*)(dvoid *, dvoid *)) 0 );
(void) OCIEnvInit( (OCIEnv **) &envhp, OCI_DEFAULT, (size_t) 0,(dvoid **) 0 );
//Allocate the handle
(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &errhp, OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0);
(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &srvhp, OCI_HTYPE_SERVER,(size_t) 0, (dvoid **) 0);
(void) OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &svchp, OCI_HTYPE_SVCCTX,(size_t) 0, (dvoid **) 0);
//Set the db link name.
(void) OCIServerAttach( srvhp, errhp, (text *)dbname, strlen(dbname), 0);
/* set attribute server context in the service context */
(void) OCIAttrSet( (dvoid *) svchp, OCI_HTYPE_SVCCTX, (dvoid *)srvhp,(ub4) 0, OCI_ATTR_SERVER, (OCIError *) errhp);
(void) OCIHandleAlloc((dvoid *) envhp, (dvoid **)&authp,(ub4) OCI_HTYPE_SESSION, (size_t) 0, (dvoid **) 0);
(void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,(dvoid *) username, (ub4) strlen((char *)username),(ub4) OCI_ATTR_USERNAME, errhp);
(void) OCIAttrSet((dvoid *) authp, (ub4) OCI_HTYPE_SESSION,(dvoid *) password, (ub4) strlen((char *)password),(ub4) OCI_ATTR_PASSWORD, errhp);
checkerr(errhp, OCISessionBegin ( svchp, errhp, authp, OCI_CRED_RDBMS,
(ub4) OCI_DEFAULT));
(void) OCIAttrSet((dvoid *) svchp, (ub4) OCI_HTYPE_SVCCTX,(dvoid *) authp, (ub4) 0,(ub4)OCI_ATTR_SESSION, errhp);
return true;
}
bool
OraConnect:isConnect()
{
if (errhp)
(void) OCIServerDetach( srvhp, errhp, OCI_DEFAULT );
if (srvhp)
checkerr(errhp, OCIHandleFree((dvoid *) srvhp, OCI_HTYPE_SERVER));
if (svchp)
(void) OCIHandleFree((dvoid *) svchp, OCI_HTYPE_SVCCTX);
if (errhp)
(void) OCIHandleFree((dvoid *) errhp, OCI_HTYPE_ERROR);
if(envhp)
(void) OCIHandleFree((dvoid *) envhp, OCI_HTYPE_ENV);
return true;
}
void
OraConnect::checkerr(OCIError *errhp,sword status)
{
text errbuf[512];
sb4 errcode = 0;
switch (status)
{
case OCI_SUCCESS:
break;
case OCI_SUCCESS_WITH_INFO:
(void) printf("Error - OCI_SUCCESS_WITH_INFO/n");
break;
case OCI_NEED_DATA:
(void) printf("Error - OCI_NEED_DATA/n");
break;
case OCI_NO_DATA:
(void) printf("Error - OCI_NODATA/n");
break;
case OCI_ERROR:
(void) OCIErrorGet((dvoid *)errhp, (ub4) 1, (text *) NULL, &errcode,
errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
(void) printf("Error - %.*s/n", 512, errbuf);
break;
case OCI_INVALID_HANDLE:
(void) printf("Error - OCI_INVALID_HANDLE/n");
break;
case OCI_STILL_EXECUTING:
(void) printf("Error - OCI_STILL_EXECUTE/n");
break;
case OCI_CONTINUE:
(void) printf("Error - OCI_CONTINUE/n");
break;
default:
break;
}
}
在調試中反而發現了一個怪問題,當我的mode設置成OCI_SHAREDOCI_THREADED,用OCIEnvCreate調用會crash,不過假如單用OCI_SHARED或OCI_THREADED就不會有問題,假如用
OCIInitialize和OCIEnvInit來替代OCIEnvCreate則沒有什么問題,不過我覺得是我自己的編譯參數不太對吧.我的環境是(oracle8.1.7,windows2000 professional,vc6(sp5)).
調用代碼.
OraConnect conn[10];
for(int i=0;i<10;i++)
{
conn[i].setUsername("skyems");
conn[i].setPassword("skyems");
conn[i].setDbname("skydb");
conn[i].Connect();
}
for(int j=0;j<10;j++)
{
conn[j].DisConnect();
}
試了試,應該是沒什么問題的.試了試,應該是沒什么問題的.h file中的extern聲明是因為oci是個c接口