VC+ADO+多线程高效、安全的读写数据库

一、问题介绍

项目需要实时获取并处理40路相机的现场图像,并将处理结果写入到数据库,采用的方案是使用多线程技术,创建40个工作者线程,每个线程建立一个数据库连接。本文仅将项目中遇到的问题以及解决方法做些记录。

二、多线程连接数据库

在单线程程序中,只需建立一个数据库连接。在多线程中,因为多线程是并行处理的(对于多核CPU来说),若按单线程方式只建立一个数据库连接,多线程共用此连接,那么必然存在排队等待的问题。比较好的方法是每个线程建立一个单独的连接。

  1. 采用ADO技术在多线程中建立多个数据库连接时,必须在每个线程中使用CoInitialize(NULL)初始化COM库。
  2. 线程结束时,必须在每个线程中使用CoUninitialize()释放COM资源。

三、实现代码

下面代码展示了如何建立多线程并在线程中建立数据库连接的过程。数据库为:SQL Server 2012,编译工具为VS2010,ADO技术。

/////// main.cpp //////////
//////////////////////////

#include "iostream"
#include "atlstr.h"
using namespace std;
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")

unsigned int __stdcall threadProc(PVOID);//工作者线程函数

int total = 40;  //工作者线程总数
int index = 0;   
void main()
{
    ::CoInitialize(NULL);//初始化COM库
    for ( int i = 0; i < total; i++)
    {
        _beginthreadex(NULL,0,threadProc,NULL,0,NULL);
    }
    getchar();  // 主线程阻塞在此处

}

//工作者线程函数
unsigned int __stdcall threadProc(PVOID)
{
    int threadId = index;
    index++;

    ::CoInitialize(NULL);//初始化COM库

    _ConnectionPtr pConn;
    pConn.CreateInstance("ADODB.Connection");
    pConn->ConnectionTimeout = 30;  //设置连接超时时间 30s
    try
    {
        pConn->Open("Driver={SQL Server};Server=LENOVO-PC01;Database=dbTest;UID=sa;PWD=mima","","",adConnectUnspecified);
    }
    catch(_com_error e)
    {
        ::MessageBox(NULL,e.Description(),_T("警告"),MB_OKCANCEL);
    }
    for (int j = 0 ; j < 100; j++)
    {
        CString strSql;
        strSql.Format(_T("insert into Table3(id,age) values( %d ,%d)"),ThreadId,j);

        _variant_t recordset;
        pConn->Execute((_bstr_t)strSql,&recordset,adCmdText);
    }
    if (pConn->State == adStateOpen )
    {
        pConn->Close();
    }
    ::CoUninitialize();//反初始化COM库
    return 0;
}

三、上述代码存在的问题

当线程数一多,使用上述代码百分百会出现问题,提示如下:

这里写图片描述

原因在于数据库建立连接是个非常消耗资源与时间的工作,同时创建大量连接,完成这些连接的耗时必将非常长,而数据库默认的连接超时为30s,一旦超过这个时间,程序就会传回超时错误。解决方法如下:

  1. 将连接超时调大,大到足够完成所有连接的创建。
  2. 连接排队创建,只有上个连接创建完成,才开始创建下一个连接,直至所有连接创建完成。

方案1:

 //设置超时时间足够大,此处为3000s
 pConn->ConnectionTimeout = 3000;  //设置连接超时时间 3000s

方案2,推荐采用,实现代码如下:

/////// main.cpp //////////
//////////////////////////
#include "iostream"
#include "atlstr.h"
using namespace std;
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")

unsigned int __stdcall threadProc(PVOID);//工作者线程函数

int total = 40;//工作者线程总数
int index = 0;
int *flag = new int[total](); // 连接创建成功标志

void main()
{
    ::CoInitialize(NULL);//初始化COM库

    HANDLE *hThread = new HANDLE[total];

    for ( int i = 0; i < total; i++)
    {
        hThread[i] = (HANDLE)_beginthreadex(NULL,0,threadProc,NULL,CREATE_SUSPENDED,NULL);
    }
    int f = flag[4];

    ResumeThread(hThread[0]);
    for (int i = 1; i < total ; i++)
    {
        while(flag[i-1] != 1)
        {
            //空转
        }
        ResumeThread(hThread[i]);
    }

    getchar();

    delete [] hThread;
    delete [] flag;
}

unsigned int __stdcall threadProc(PVOID)
{
    int Threadid = index;

    ::CoInitialize(NULL);//初始化COM库

    _ConnectionPtr pConn;
    pConn.CreateInstance("ADODB.Connection");
    pConn->ConnectionTimeout = 30;
    try
    {
        pConn->Open("Driver={SQL Server};Server=LENOVO-PC01;Database=huayuTest;UID=sa;PWD=MIMA","","",adConnectUnspecified);
    }
    catch(_com_error e)
    {
        ::MessageBox(NULL,e.Description(),_T("!!!!"),MB_OKCANCEL);
    }

    cout << "Connect:" <<index<<" has been established"<<endl;
    flag[index] = 1;  // 
    index++;

    for (int j = 0 ; j < 100; j++)
    {
        CString strSql;
        strSql.Format(_T("insert into Table3(id,age) values( %d ,%d)"),Threadid,j);

        _variant_t recordset;
        pConn->Execute((_bstr_t)strSql,&recordset,adCmdText);
    }
    if (pConn->State == adStateOpen )
    {
        pConn->Close();
    }

    ::CoUninitialize();//反初始化COM库
    return 0;
}

四、总结

多线程并发访问数据库,解决方法是在每个线程中建立一个数据库连接,需要注意的两点如下:

  1. 必须在每个线程中都调用CoInitialize(NULL)和CoUninitialize()来初始化COM库和释放COM库资源。
  2. 同时创建多个数据库连接时,需要注意数据库连接超时问题,解决方法是分批创建数据库连接。

转载请注明作者和出处:http://blog.csdn.net/holamirai,未经允许请勿用于商业用途。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: vc是指Venture Capital(风险投资),是指投资者将资金投入于有潜力的初创企业或创新项目中,以获取高额回报的一种投资方式。vc不仅提供资金支持,还会向项目方提供战略指导、市场拓展、管理经验等方面的支持,帮助企业实现更快的发展。 在vc投资过程中,经常需要使用http接口调用json。HTTP是一种用于传输超文本的协议,而json是一种轻量级的数据交换格式。通过HTTP接口,投资者可以向初创企业的服务器发送请求,获取关于企业经营状况、财务数据、市场前景等信息,并将这些信息以json格式进行传输。 通过http接口调用json,vc投资者可以实时了解企业的运营情况和财务状况,以便做出更好的投资决策。同时,通过json可以将复杂的数据进行结构化处理,便于投资者进行数据分析和挖掘。投资者可以通过自己搭建的数据分析平台,将从http接口获取的json数据导入到系统中,进行数据处理和建模。这样,投资者可以更好地了解企业的市场定位、盈利模式、用户增长情况等,并根据这些数据进行风险评估和投资决策。 总之,vc投资者通过http接口调用json,可以实时获取企业的关键数据,在投资决策上提供更有针对性的支持。而企业也能通过向vc投资者提供http接口和json数据,展示自身的潜力和价值,从而吸引更多的投资。这种基于http接口调用json的交互方式,能够促进vc投资与初创企业之间的信息流动,进而推动创新与发展。 ### 回答2: VC(Voice Conversion,声音转换)是一种将一个人的语音转换为另一个人的语音的技术。在VC中,可以使用HTTP接口来进行JSON格式的调用。 HTTP接口调用是一种通过网络发送HTTP请求并接收HTTP响应的方式。JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式,常用于前后端之间的数据传输。 在使用VC的HTTP接口调用JSON时,可以按照以下步骤进行: 1. 构建HTTP请求:使用程序或工具发送HTTP POST请求,指定接口的URL,并设置请求头部,告知服务器发送的数据格式是JSON。 2. 组织JSON数据:在请求体中,构建JSON数据,根据接口的要求填入相应的参数和数值。例如,可能需要指定要转换的语音文件路径、转换目标的人物特征等等。将这些信息以JSON格式组织起来。 3. 发送HTTP请求:将组织好的HTTP请求发送到服务器。服务器接收到请求后,会解析请求体中的JSON数据,并根据其中的参数进行相应的处理。 4. 处理请求:根据请求中包含的参数,服务器进行语音转换的计算和处理。可能涉及到语音信号处理、音素映射、声码器等复杂的算法和模型。 5. 返回JSON响应:服务器将处理结果组织成JSON格式的数据,并将其作为HTTP响应的内容返回给客户端。客户端接收到响应后,可以通过解析JSON数据来获得转换后的语音文件或其他相关信息。 通过VC的HTTP接口调用JSON,可以方便地实现语音转换的功能。这种方式可以让开发者使用自己熟悉的编程语言和工具进行开发,并且可以灵活地将语音转换集成到自己的应用程序中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值