本帖最后由 share2 于 2010-09-19 14:59:17 编辑

解决方案 »

  1.   

    大家给点建议吧,这两天被这个弄得非常郁闷。
    oracle文档里面关于连接池提到:
    thread1()
    {
    EXEC SQL CONTEXT ALLOCATE :ctx1;
    EXEC SQL CONNECT :uid AT :TC1 USING :db_string;
    ...
    }
    thread2()
    {
    EXEC SQL CONTEXT ALLOCATE :ctx2;
    EXEC SQL CONNECT :uid AT :TC2 USING :db_string;
    ...
    }
    thread3()
    {
    EXEC SQL CONTEXT ALLOCATE :ctx3;
    EXEC SQL CONNECT :uid AT :TC3 USING :db_string;
    EXEC SQL AT :TC3 SELECT count(*) into :count FROM emp;
    ...
    }
    thread4()
    {
    EXEC SQL CONTEXT ALLOCATE :ctx4;
    EXEC SQL CONNECT :uid AT :TC4 USING :db_string;
    ...
    }
    这些线程的连接还有会话怎么回收呢?
      

  2.   

    这个问题不是太懂,不好意思帮不上忙,参考下这个文档,会不会有你想要的结果
    http://wenku.baidu.com/view/e3f0114bcf84b9d528ea7aed.html
      

  3.   

    这个应用是比较偏,很多人遇不到这个问题,相关资料也少。
    oracle的pro*c/c++ procompiler A97269文档有关多线程、连接池的内容也被我翻来覆去看了好多遍,头都大了。到底怎么配置怎么编码讲的不全,按我的理解加上连接池,会话、连接都不受控制。
      

  4.   

    过了国庆节现在才回来。
    我用的解决方案是这样的,首先还是用编译参数
    proc db_fun.pc THREADS=YES CPOOL=YES CMAX=5 CMIN=1 CINCR=2
    控制连接数,然后每次初始化一定数量的sql_context存放到空闲池,每次需要使用数据库操作时从空闲池取,用完又放进空闲池。每一个sql_context会产生一个会话,每个线程如果都新建一个sql_context然后按照顶楼代码那样,数据库资源需要等待进程结束时才真正释放,这样处理就就会看到会话越来越多,直到数据库会话限制。部分代码如下,请指正:
    /******************************************************************************
    * 函 数 名:ConnectDatabase
    * 编写日期:2010.09
    * 函数功能:根据配置文件中连接池连接数建立程序与ORACLE的连接池
    * 输入说明:
    * 返 回 值:0:连接成功, -1:连接失败
    * 修改记录:
    * 注意事项:
    *******************************************************************************/
    int ConnectDatabase( char *azp_UserName,   /*用户名*/
                         char *azp_Password,   /*密码*/
                         char *azp_DbString,   /*DB连接串*/
                          int  azp_dbcpool     /*db连接池连接数*/
                        )
    {
        struct sqlca sqlca;
        EXEC SQL ENABLE THREADS;    /* 初始化数据库上下文池 */
        int i = 0;
        while(i < azp_dbcpool)
        {
            sql_context* sql_ctx = malloc(sizeof(sql_context));        EXEC SQL CONTEXT ALLOCATE :*sql_ctx;
            EXEC SQL CONTEXT USE :*sql_ctx;
            EXEC SQL WHENEVER SQLERROR DO SqlError(sqlca.sqlerrm.sqlerrmc);        printf("begin to connect database [%s/%s@%s]........", azp_UserName, azp_Password, azp_DbString);
            EXEC SQL CONNECT :azp_UserName IDENTIFIED BY :azp_Password AT db_name USING :azp_DbString;        if (sqlca.sqlcode != 0)
            {
                printf("Can't Connect to %s!\n", azp_DbString);
                return -1;
            }
            else
            {
                printf("OK!\n");
            }        /* 将初始化完成的上下文保存到空闲上下文链表 */
            add_free_node(sql_ctx);        i++;
        }    /*Create mutex for transaction retrieval */
        if (pthread_mutex_init(&mutex,NULL))
        {
            printf("Can't initialize mutex\n");
            return -1;
        }
        return 0;
    }/******************************************************************************
    * 函 数 名:free_sqlctx_list
    * 编写日期:2010.09
    * 函数功能:释放数据库上下文空闲队列,回收数据库资源
    * 输入说明:
    * 返 回 值:
    * 修改记录:
    * 注意事项:
    *******************************************************************************/
    int free_sqlctx_list()
    {
        while(NULL != p_free_ctx_head)
        {
            FREE_NODE* p_tmp = p_free_ctx_head;
            p_free_ctx_head = p_free_ctx_head->p_next;        EXEC SQL CONTEXT USE :*(p_tmp->ctx);        printf("free database connect[%d]........", free_sql_ctx_count);
            EXEC SQL AT db_name COMMIT WORK RELEASE;
            if( sqlca.sqlcode != 0)
                printf("cant disconnect!\n");
            else
                printf("disconnect!\n");        printf("free sql_context[%d]........",free_sql_ctx_count--);
            EXEC SQL CONTEXT FREE :*(p_tmp->ctx);
            if( sqlca.sqlcode != 0)
                printf("cant free sql_context!\n");
            else
                printf("free sql_context!\n");        free(p_tmp->ctx);
            p_tmp->ctx = NULL;
            free(p_tmp);
            p_tmp = NULL;
        }    return 0;
    }/******************************************************************************
    * 函 数 名:add_free_node
    * 编写日期:2010.09
    * 函数功能:增加一个空闲的数据库上下文到空闲队列
    * 输入说明:
    * 返 回 值:
    * 修改记录:
    * 注意事项:
    *******************************************************************************/
    void add_free_node(sql_context* ctx)
    {
        if (pthread_mutex_lock(&mutex))
            printf("Can't lock mutex\n");    FREE_NODE* p_tmp = malloc(sizeof(FREE_NODE));
        memset(p_tmp,0x00,sizeof(FREE_NODE));
        p_tmp->ctx = ctx;
        p_tmp->p_next = p_free_ctx_head;    p_free_ctx_head = p_tmp;    free_sql_ctx_count++;    #if TEST
        printf("======================================增加空闲上下文,目前空闲总数量[%d]\n",free_sql_ctx_count);
        #endif    if (pthread_mutex_unlock(&mutex))
            printf("Can't unlock mutex\n");    return;
    }/******************************************************************************
    * 函 数 名:get_free_node
    * 编写日期:2010.09
    * 函数功能:从空闲队列获取一个空闲的数据库上下文
    * 输入说明:
    * 返 回 值:
    * 修改记录:
    * 注意事项:
    *******************************************************************************/
    sql_context* get_free_node()
    {
        if (pthread_mutex_lock(&mutex))
            printf("Can't lock mutex\n");    sql_context* ctx_return = NULL;    FREE_NODE* p_tmp = p_free_ctx_head;
        if (p_free_ctx_head != NULL)
        {
            ctx_return = p_free_ctx_head->ctx;
            p_free_ctx_head = p_free_ctx_head->p_next;        free(p_tmp);
            p_tmp = NULL;        free_sql_ctx_count--;
        }    #if TEST
        printf("======================================获取空闲上下文,目前空闲总数量[%d]\n",free_sql_ctx_count);
        #endif    if (pthread_mutex_unlock(&mutex))
            printf("Can't unlock mutex\n");    return ctx_return;
    }
    /******************************************************************************
    * 函 数 名:select_base_info
    * 编写日期:2009.8
    * 函数功能:实际业务
    * 输入说明:
    * 返 回 值:0:成功, -1:失败
    * 修改记录(如果有)
    * 注意事项:
    *******************************************************************************/
    int select_base_info(STRU_MSG *asp_recv_msg,STRU_MSG *asp_send_msg,STRU_PARAM *asp_Param)
    {
        struct sqlca sqlca;    sql_context* ctx = get_free_node();
        if (NULL == ctx)
        {
            sprintf(asp_send_msg->datatrans,"0001%-64s","内部错误,系统正忙");
            return(-1);
        }    EXEC SQL CONTEXT USE :*ctx;    EXEC SQL AT db_name ……;    add_free_node(ctx);
        return(0);
    }
    相应结构
    /*空闲数据库上下文队列节点*/
    typedef struct
    {
        sql_context * ctx;
        struct FREE_NODE* p_next;
    } FREE_NODE;/*空闲数据库上下文队列头指针*/
    FREE_NODE* p_free_ctx_head = NULL;
    /*空闲数据库上下文队列计数*/
    int free_sql_ctx_count = 0;
    pthread_mutex_t mutex;
      

  5.   

    如果没有使用连接池,那么需要自己控制连接个数,每次使用"EXEC SQL CONNECT ……"都会产生一个dedicated 连接,一个连接里面是可以使用多个sql_context的,要注意的是这些数据库资源都是只有在程序结束的时候才能回收。
      

  6.   

    是不是当一个连接池的所有上下文都结束,就表示这个连接池用完,所以又开了一个新的连接池!如果多个线程一直使用对应的上下文,就不会增加连接,只要都释放,就会增加,我是这样理解的!
    关于连接池为什么进程退出才释放连接,我感觉是oracle配置问题,网上有类似的帖子!!!
      

  7.   

    #include <sqlca.h>
    #include <sqlda.h>
    #include <sqlcpr.h>
    #include <OCI.h>#define NUM 100class StdDBClass
    {
    public:
    EXEC SQL BEGIN DECLARE SECTION;
    sql_context ctx[100];
    EXEC SQL END DECLARE SECTION; StdDBClass()
    {
    } ~StdDBClass()
    {
    } void UseThread()
    {
    EXEC SQL ENABLE THREADS;
    }

    void Allocate()
    {
    for(int i=0; i<NUM; ++i)
    {
    EXEC SQL CONTEXT ALLOCATE :ctx[i];
    }
    }

    int OpenDB(const char* usr, const char* pwd,const char* szServerName, sql_context ctx)
    {
    EXEC SQL BEGIN DECLARE SECTION;
    char username[64];
    char passwd[64];
    char server[64];
    EXEC SQL END DECLARE SECTION;

    strcpy(username,usr);
    strcpy(passwd,pwd);
    strcpy(server,szServerName);

    struct sqlca sqlca;

    EXEC SQL CONTEXT USE :ctx;
    EXEC SQL CONNECT :username IDENTIFIED BY :passwd USING :server;

    if (sqlca.sqlcode != 0) 
    {
    printf( "连接oracle数据库失败!");
    return -1;
    }

    return 0;
    } int CloseDB(sql_context ctx)
    {
    struct sqlca sqlca;

    EXEC SQL CONTEXT USE :ctx;
    EXEC SQL COMMIT WORK RELEASE;
    EXEC SQL CONTEXT FREE :ctx;
     
    if( sqlca.sqlcode != 0 )
    {
    printf( "断开数据库连接失败!%d:%s\n",sqlca.sqlcode,sqlca.sqlerrm.sqlerrmc ); 
    return -1; 
    }

    return 0;
    }

    void Free()
    {
    for(int i=0; i<NUM; ++i)
    {
    EXEC SQL CONTEXT FREE :ctx[i];
    }
    }
            
             ...
    };
      

  8.   

    你好,问个问题,sqlca是全局变量,为了解决冲突,在每个线程内定义了各自的局部struct sqlca sqlca;
    这样是可行的,但是我不想每个函数都定义一个struct sqlca sqlca;所以就将线程主函数的定义的sqlca给当成指针传入其他函数了,所以其他函数在使用sqlca的时候是sqlca->sqlcode; 使用printf是可以正常打印的的,但是一旦执行了EXEC SQL ~~~的语句,程序立即崩溃,请问各位大侠遇见过吗?!
      

  9.   

    你好楼主,请问你怎么不适用EXEC SQL ENABLE THREADS; http://linux.chinaunix.net/techdoc/develop/2005/11/05/924838.shtml