본문 바로가기
Programming/Tips(C++,C#)

초급. 간단한 OLEDB 사용하기

by 곰네Zip 2008. 7. 10.
출처 : Devpia
원분보기 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=7041&ref=7041 <<클릭클릭!

등급 : 초급

ADO oledb를 이용한 간단한 DB조작에 관련된 강좌입니다.
아시겠지만 DB조작은 ODBC를 이용하거나 OLEDB 등을 이용해 가능합니다.
ODBC는 배포시 ODBC설정등을 해줘야(코드로 대체할 수 있습니다.) 하므로 귀찮기에 전 VB건 ASP건 VC건 모두 OLEDB로 처리하는 편입니다.
짧은 경험상 책을 통한 지식(클래스를 이용한 DB조작)은 딱딱하기 그지 없습니다.
이는 위에 나열한 언어와 관련된 책 모두 동일했습니다.
(특히 VB로 처음 DB조작이란걸 경험했을때 DAO 컨트롤을 통해 레코드를 이동시키며 공부했을때의 그 막막함이란..ㅡㅡ
 Join이란 녀석 자체도 몰랐기에 테이블 만큼 컨트롤 생성하고 억지로 이것 저것..ㅡㅡ)
여튼.. 잡설은 그만두고.. 간단한 사용 예를 들어볼까 합니다.
[사전인지사항]
MyAdodb.h, MyAdodb.cpp : DB관련 변수와 초기화 연결등을 담당합니다.
SimpleAdoDlg.h SimpleAdoDlg.cpp : 실질적인 DB조작을 담당합니다.
[Step 1 : MyAdodb.h, MyAdodb.cpp]
1.프로젝트 하나를 생성합니다.
2.StdAfx.h를 열어 #import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF", "adoEOF")를 복사해 넣습니다.
3.COM 라이브러리를 초기화해야 하니 CoInitialize(0);를 생성자에 포함시킵니다.
   이와 반대로 소멸자엔 CoUninitialize();를 삽입합니다.  
4. 커넥션과 커멘드 그리고 레코드셋 변수를 생성해줍니다.
    _ConnectionPtr m_pConn; // 커넥션은 말 그대로 DB와의 연결을 담당합니다. DB의 Open, Close...
    _RecordsetPtr m_pRs;      // 레코드셋 또한 말 그대로 조회결과인 레코드들을 담당합니다. 이녀석을 통하여 조회된 결과를 Movenext등을 이용해 원하는 결과물을 얻어낼 수 있습니다.
    _CommandPtr m_pComm;// 커멘드는 이 역시 명령과 관련된 녀석입니다. Update를 해라던지...
5.DB와 연결을 합니다.
BOOL CMyAdodb::InitDB(CString strUserId, CString strPassWord, CString strDbIp, CString strDbName, CString strPort)
{  
    CString strConn = "";
    strConn.Format("User ID=%s;Password=%s;Data Source=%s;"
                    "Initial Catalog=%s;Network Address=%s,%s;"
                    "Network Library=dbmssocn",
                    strUserId, strPassWord, strDbIp, strDbName, strDbIp, strPort);
    m_pConn = new _ConnectionPtr("ADODB.Connection");
    m_pRs = new _RecordsetPtr("ADODB.Recordset");
    m_pRs->CursorType = adOpenDynamic;
    m_pComm = NULL;
    m_pConn->Provider = "SQLOLEDB";
    m_pConn->ConnectionString = strConn.GetBuffer(0);  // 접속 스트링 설정.
    try
    {
        m_pConn->Open("","","", adConnectUnspecified);
    }catch(...)
    {
        return FALSE;
    }

    m_pComm.CreateInstance(__uuidof(Command));
    m_pComm->ActiveConnection = m_pConn;
    m_pComm->CommandType = adCmdText;

    return TRUE;
}

여기 까지 했다면 일단 사전 준비단계는 끝난거라봐도 무관합니다.
이제부턴 실질적인 연결작업과 조회 수정등을 해 볼 차례입니다.

[Step 2 SimpleAdo.h, SimpleAdo.cpp]
1.MyAdodb.h를 SimpleAdoDlg.h에 포함시키고 클래스를 만듭니다.
#include "MyAdodb.h"
CMyAdodb m_MyAdodb;

2.SimpleAdoDlg.cpp에서 DB연결 및 조작을 해봅니다.
  먼저 DB연결 문자열을 생성시킵니다.
  쿼리를 날렸을때 이녀석이 어떤 DB에 어떤 정보로 로긴등을 하여 조작이 가능한지에 대한 문자열입니다.
  잘 모르신다면 아래 강좌를 참조하시면 쉽게 설명되어있습니다.
http://www.devpia.com/Forum/BoardView.aspx?no=6840&page=1&Tpage=1&forumname=vc_lec&stype=&ctType=&answer=&KeyR=nameid&KeyC=

MS-SQL
을 기준으로
User ID : DB에 로그인할 아이디 (SA정도가 됩니다.)
Password : 로그인할 아이디의 비밀번호
Data Source : MS-SQL이니 특정 아이피가 들어갑니다. 만약 MDB라면 해당 로컬 경로가 들어가있을겁니다.
Initial Catalog : DB의 이름입니다.
Network Address : MS-SQL이니 특정 아이피가 들어갑니다. 만약 MDB라면 해당 로컬 경로가 들어가있을겁니다. 특정 포트로 DB가 설정이 되어있지 않다면 기본포트인 1433이 입력됩니다.
Network Library : 모르겠군요. 책을 보면 나와있을겁니다. 죄송^^

Ex)
User ID=USERID;Password=PASSWORD;Data Source=XXX.XXX.XXX.XXX;Initial Catalog=DBNAME;Network Address=XXX.XXX.XXX.XXX,1433;Network Library=dbmssocn

위 정보를 토대로 Step1의 5번에서 만든 DB연결 함수를 호출합니다.
    if(m_MyAdodb.InitDB("USERID", "PASSWORD", "XXX.XXX.XXX.XXX", "DBNAME", "1433") == FALSE)
    {
        MessageBox("디비접속에러입니다. 작업을 진행할 수 없습니다.", "SIMPLEDB", MB_ICONSTOP);
        GetParentOwner()->PostMessage(WM_CLOSE);
        return;
    }   

3.DB와의 연결이 성공하였으니 가장 기본이 되는 조회(Select)를 해보겠습니다.
    // 알맞은 쿼리를 대입하십시요. join이든 union이든.. (당연하지만..ㅡㅡ)
    m_MyAdodb.m_pComm->CommandText = "Select * From Test_Tbl where 어쩌고 저쩌고";

    try
    {
        m_MyAdodb.m_pRs = m_MyAdodb.m_pComm->Execute(NULL,NULL,adCmdText);  // 저장된 select문을 수행합니다.
    }
    catch(...)
    {   // 에러일 경우 메세지 박스를 출력하고 조회 작업을 종료해 버립니다.(에러가 날 경우는 거의 없습니다.)
        MessageBox("조회 오류!", "SIMPLEDB", MB_ICONSTOP);
        return;
    }

    // 결과가 존재하지 않음
    if(m_MyAdodb.m_pRs->adoEOF)    
    {
        m_MyAdodb.m_pRs->Close();   // 레코드셋을 닫는다.(항상 레코드셋 오픈 후엔 닫아주는 작업을 수행해야 합니다.)
        MessageBox("조건에 맞는 데이터가 없습니다.", "SIMPLEDB", MB_ICONINFORMATION);
        return;
    }   

    _variant_t Field_1;     // 필드명입니다.(알맞은 필드명을 나열하십시요)
    _variant_t Field_2;     // 필드명입니다.

    char szField1[10+1]         = {'\0',};  // 필드명과 1:1대응하게 변수를 선언하십시요
    char szField2[10+1]         = {'\0',};

    // 조회된 레코드의 끝까지 루핑을 돌며 데이터를 확인합니다.
    while(!m_MyAdodb.m_pRs->adoEOF)
    {
        Field_1         = m_MyAdodb.m_pRs->Fields->GetItem("field_1")->GetValue();  // 해당 필드를 선언한 variant변수에 저장합니다.
        Field_2         = m_MyAdodb.m_pRs->Fields->GetItem("field_2")->GetValue();
 
        strcpy(szField1,    (char*)((_bstr_t)Field_1));                             // 저장된 variant변수를 조작이 편한 char변수에 복사합니다.
        strcpy(szField2,    (char*)((_bstr_t)Field_2));
        // 리스트 컨트롤을 추가하셨거나 화면에 출력하실 생각이 있으시다면
        // 루핑을 돌리며 값을 채워넣는 작업을 이부분에서 하시면 됩니다.

        m_MyAdodb.m_pRs->MoveNext();    // 레코드셋을 다음으로 이동시킵니다.
    }
    m_MyAdodb.m_pRs->Close();           // 레코드셋을 닫아줍니다.
그림으로 해보면..



4.Update를 해보겠습니다.
    _variant_t LRowCount;   // Update가 적용된 레코드의 로우수
    long lrowcount = 0;     // 적용된 variant형을 레코드의 로우수 저장
    char CommandString[400+1]={'\0',};
    strcpy(CommandString, "Update Test_Tbl set Field_1 ='01', Field_2='02' Where User='senosora'");    // 알맞는 update쿼리를 적용하십시요.
    m_MyAdodb.m_pComm->CommandText = CommandString;        
   
    try
    {
        m_MyAdodb.m_pComm->Execute(&LRowCount,NULL,adCmdText); // Update 실행
    }
    catch(...)
    {
        // 에러일 경우 메세지 박스를 출력하고 update 작업을 종료해 버립니다.(에러가 날 경우는 update문 오류.)
        MessageBox("Update 오류!", "SIMPLEDB", MB_ICONSTOP);
        return;
    }
   lrowcount = atol((char*)((_bstr_t)LRowCount));  // variant형을 long형에 저장  

    if(lrowcount == 0) // 업데이트된게 없다.
    {
        MessageBox("Update 적용된 레코드 없음!", "SIMPLEDB", MB_ICONSTOP);  
        return;
    }

여기까지입니다.
제 지식이 DB에 관해 command객체는 어떠어떠하고 레코드셋은 어떠하며 속도가 어떻다라 논할 실력이 된다면야 좋겠지만 그렇다고 책을 그대로 베껴놓을수도 없고.. 해서 배경지식은 적지 못했습니다. 틀린점이 있다면 바로잡아 주시면 감사하겠습니다. 첨부되는 파일은 실행하면 DB가 없으니..에러가 납니다. 그냥 눈으로 보시면 이해가 빠르지 않을까 싶어 첨부합니다. 테스트 하시려면 DB구성부터 하셔야 합니다. 근데.. 주절 주절 해놓고 보니 어째 더 복잡해보이는군요.ㅡㅡ

MYSQL을 사용하시려면 DB연결부분만 MYSQL로 변경해주시면 동일하게 사용이 가능합니다.
추가 : 대충 이런식으로 알고 있습니다. mysql을 잘 모르는데.. localhost라면 mysql은 pwd를 안넣더군요..
        // MySql
        strcpy(ConStr,"Driver={MySQL};server=");
        strcat(ConStr,DBIP);

        if(strcmp(DBIP, "localhost") == 0)
        {       
            strcat(ConStr,";Uid=root;pwd=;Database=yourdbname");
        }
        else
        {       
            strcat(ConStr,";Uid=root;pwd=yourpassword;Database=yourdbname");
        }

         pConn = _ConnectionPtr("ADODB.Connection");
            pRS =  _RecordsetPtr("ADODB.Recordset");
            pRS->CursorType = adOpenDynamic;
            pComm = NULL;
            pConn->ConnectionString = ConStr;  // 접속 스트링 설정.

            try
           {
                pConn->Open("","","", adConnectUnspecified);
            }catch(_com_error &e)
            {
                _bstr_t bstrSource(e.Source());
                _bstr_t bstrDescription(e.Description());          

                AfxMessageBox("MySQL DB 접속 에러");
                exit(1);
            }
            pComm.CreateInstance(__uuidof(Command));
            pComm->ActiveConnection = pConn;
            pComm->CommandType = adCmdText;
        }

*주의할점 *
  m_pConn = new _ConnectionPtr("ADODB.Connection");
  식의 Open은 곤란하다고함.
  _com_ptr_t 타입의 COM 인터페이스는 new를 이용한 생성시 메모리 누수 발생.. ㄷㄷㄷ
  m_pComm.CreateInstance("ADODB.Connection"); 으로 생성을 해줄것

반응형

댓글