ODBC를 이용한 MFC 데이터베이스 프로그래밍

2020. 12. 2. 22:47·C, C++, MFC

ODBC는 응용 프로그램과 DBMS간의 표준 인터페이스를 제공한다. 따라서 ODBC를 이용하는 응용 프로그램은 ODBC 드라이버를 제공하는 어떤 DBMS와도 연동할 수 있다. 즉, Oracle, MS SQL 무엇을 사용하든 상관없이 ODBC 드라이버만 제공하면 된다.

* DBMS : DataBase Management System

 

MFC는 ODBC를 이용한 데이터베이스 프로그래밍을 할 수 있도록 다음과 같은 클래스를 제공해준다.

 

CDatabase 클래스

데이터베이스와의 연결을 관리한다.

 

CRecordset 클래스

데이터의 추가, 삭제, 수정, 검색, 정렬 등에 관련된 기능이 있다.

 

* 참고. MS SQL ODBC 데이터 원본 추가 방법

더보기

1. ODBC 데이터 원본 관리자를 열고 [추가] 버튼을 클릭하여 DSN를 추가한다.

* DSN (Data Source Name)

 

2. SQL Server를 클릭하고 SQL Server를 선택 후 [마침] 버튼을 누른다.

 

3. DSN 이름과 서버 주소를 입력한다. [다음] 버튼을 클릭한다.

나는 내 PC에 설치했으므로 localhost (또는 127.0.0.1)로 설정했다.(\sqlexpress01은 sql 인스터스명)

 

4. 3번에서 입력한 SQL Server에 로그인 할 계정 정보를 입력한다. [다음] 버튼을 클릭한다.

 

5. 기본 데이터베이스를 선택한다. [다음] 버튼을 클릭한다.

 

6. [마침] 버튼을 클릭한다.

 

7. [데이터 원본 테스트] 버튼을 클릭하여 DB와의 연결을 확인한다. 정상적으로 연결됨을 확인하면 [확인] 버튼을 클릭하여 마무리한다.

 

8. ODBC 데이터 원본 관리자에 추가된 DSN을 확인할 수 있다.

 

Sample Program

* DB는 Microsoft SQL Server 2019 이용

* DB에 User (Name, Mobile, Birthday, Gender)라는 테이블을 생성하였음

* ODBCTest라는 이름의 MFC 프로젝트를 생성한 뒤 m_ctrlList 멤버 변수를 갖는 리스트컨트롤 추가하였음

 

1. include afxdb.h

ODBC를 사용하기 위해서는 stdafx.h 파일에 afxdb.h를 include 해줘야 한다.

// Stdafx.h
#include <afxdb.h>	// ODBC

 

2. CDatabase, CRecordset 멤버변수 추가

// ODBCTestView.h
protected:
	CDatabase m_db;
	CRecordset *m_pRs;

 

3. 리스트컨트롤 칼럼 추가

void CODBCTestView::OnInitialUpdate()
{
	// ...

	// add list column
	m_ctrlList.InsertColumn(0, "이름", LVCFMT_LEFT, 80);
	m_ctrlList.InsertColumn(1, "전화번호", LVCFMT_LEFT, 150);
	m_ctrlList.InsertColumn(2, "생일", LVCFMT_LEFT, 150);
	m_ctrlList.InsertColumn(3, "성별", LVCFMT_LEFT, 80);

	// ...
}

 

4. Select Sample

DB를 조회하여 레코드를 리스트컨트롤에 추가하는 예제이다.

void CODBCTestView::SelectData()
{
	try
	{
		// DSN 정보를 이용하여 DB open
		BOOL bOpen = m_db.OpenEx("DSN=DBTest;SERVER=localhost\\sqlexpress01;PORT=1433;UID=sa;PWD=1234;DATABASE=Test;");

		if ( bOpen )
		{
			// recordset을 받아올 CRecordset 객체
			m_pRs = new CRecordset( &m_db );

			// query를 날려 recordset을 받아옴
			BOOL bOpen = m_pRs->Open( CRecordset::snapshot, "SELECT Name, Mobile, Birthday, Gender FROM [User]" );

			if ( bOpen )
			{
				CString strData;
				int iRow = 1;
				BOOL bIsEOF = m_pRs->IsEOF();

				if ( !bIsEOF )
				{
					// MoveFirst() : 첫 번째 row로 이동
					// IsEOF() : 현재가 마지막이면 1 리턴
					// MoveNext() : 다음 row로 이동
					for ( m_pRs->MoveFirst(); !m_pRs->IsEOF(); m_pRs->MoveNext() )
					{
						// 조회한 테이블의 칼럼 수
						int iFieldCnt = m_pRs->GetODBCFieldCount();

						for ( int iCol = 0; iCol < iFieldCnt; iCol++ )
						{
							// iCol번째의 필드 값을 읽어 strData에 넣어줌
							m_pRs->GetFieldValue( iCol, strData );

							// insert list control
							if ( iCol == 0 )
								m_ctrlList.InsertItem( iRow-1, strData );
							else
								m_ctrlList.SetItemText( iRow-1, iCol, strData );
						}

						iRow++;
					}
				}
			}
			else
			{
				AfxMessageBox("Query Fail..");
			}
		}
		else
		{
			AfxMessageBox("DB Open Fail..");
		}
	}
	catch ( CException *e )
	{
		e->ReportError();
	}

	// 사용 후 CRecordset, CDatabase 순으로 종료
	if ( m_pRs->IsOpen() )
		m_pRs->Close();
	if ( m_db.IsOpen() )
		m_db.Close();
}

* Snapshot : 현재 데이터베이스의 이용이 끝난 다음 갱신된 내용을 저장하는 것
* Dynaset : 갱신이 되는 순간 바로 수정을 하는 것
* 보통 ODBC는 Snapshot을 이용하고 DAO는 Dynaset을 이용한다. ODBC는 한 곳에서만 데이터베이스를 이용하는 것이 아니라 여러 곳에서 한 개의 데이터베이스를 읽고 수정하기 때문에 자신이 수정한 내용이 완벽할 경우에만 기록을 해야지 데이터를 잘못 기록하면 다른 곳에서 사용하다가 오류가 발생할 수 있기 때문이다. DAO는 개인 PC에서 단일적으로 사용하기 때문에 이런 오류가 없고 그렇기 때문에 바로바로 수정을 하는 방식을 택하게 된다.

 

5. Insert/Update/Delete Sample

Insert, Update, Delete는 ExecuteSQL() 함수를 이용한다. 내부 쿼리만 바꿔주면 된다.

void CODBCTestView::InsertData()
{
	try
	{
		// DSN 정보를 이용하여 DB open
		BOOL bOpen = m_db.OpenEx("DSN=DBTest;SERVER=localhost\\sqlexpress01;PORT=1433;UID=sa;PWD=kimgopa;DATABASE=Test;");

		if ( bOpen )
		{
			try
			{
				m_db.ExecuteSQL("INSERT INTO [User] (Name, Mobile, Birthday, Gender) VALUES ('김고파', '010-2222-3333', '2020-12-03', 'f')");
			}
			catch ( CException *e )
			{
				e->ReportError();
			}
		}
		else
		{
			AfxMessageBox("DB Open Fail..");
		}
	}
	catch ( CException *e )
	{
		e->ReportError();
	}

	// 사용 후 CRecordset, CDatabase 순으로 종료
	if ( m_pRs->IsOpen() )
		m_pRs->Close();
	if ( m_db.IsOpen() )
		m_db.Close();
}

 

 

**

select 쿼리를 작성할 때 * (all)로 조회를 하면 나중에 테이블이 변경되었을 때 에러가 발생할 수 있다. 그러므로 필요한 칼럼만 select 해 오도록 하자.

 

 

저작자표시 비영리 변경금지 (새창열림)

'C, C++, MFC' 카테고리의 다른 글

TCP/IP 프로그래밍 - 채팅 프로그램  (0) 2021.01.06
TCP/IP 프로그래밍 - 범용 소켓 클래스  (0) 2020.12.31
TCP/IP 프로그래밍 - 소켓 통신  (0) 2020.12.19
Visual Studio 2008 MFC 프로젝트 생성  (0) 2020.11.30
MFC란?  (0) 2020.11.28
'C, C++, MFC' 카테고리의 다른 글
  • TCP/IP 프로그래밍 - 범용 소켓 클래스
  • TCP/IP 프로그래밍 - 소켓 통신
  • Visual Studio 2008 MFC 프로젝트 생성
  • MFC란?
김고파
김고파
채워나가는 중
  • 김고파
    개발자 김고파
    김고파
  • 전체
    오늘
    어제
    • all
      • C, C++, MFC
        • 따배C++
      • Qt
      • OpenCV
      • Data Structure
      • Dev Tools
      • JAVA
  • 링크

    • github
    • 네이버블로그
    • BOJ
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
김고파
ODBC를 이용한 MFC 데이터베이스 프로그래밍
상단으로

티스토리툴바