비주얼 스튜디오에 SQL Server 데이터베이스를 연결해보자
로컬에서도 데이터베이스에 접근할 수도 있고 외부 컴퓨터에서도 데이터베이스에 접근할 수도 있기 때문에,
두 방법 모두 포용하기 위해 TCP 프로토콜을 허용하는 방법으로 알아보려고 한다
먼저 TCP 프로토콜을 허용해주기 위해

SQL Server 2022 구성 관리자에서

프로토콜 TCP/IP를 사용으로 바꿔주고

SSMS의 기본 인스턴스에서 특성을 들어가

보안에서 SQL Server 및 Windows 인증 모드로 변경하고 OK

위와 같이 인스턴스를 재시작해주자

비주얼 스튜디오에 접속할 아이디와 비밀번호를 생성하고 해당 아이디에 admin 권한을 부여한다
아이디랑 비밀번호 기억!

외부에서 서버로 활용할 (DB가 깔려있는) 컴퓨터에 접속할 수 있도록 방화벽에서 포트를 열어줘야 한다





위와 같이 설정을 해주자

그러면 이렇게 인바운드 규칙이 추가된다

서버 컴퓨터의 IPv4 주소를 확인하고 기억해야 한다
이제 ODBC에 대하여 알아보자
ODBC는 Open Database Connectivity로 마이크로소프트가 만든 DB 접근 API이다
ODBC를 사용하면 여러 종류의 데이터베이스도 항상 같은 방법으로 DB와 응용프로그램을 연결할 수 있다
그렇기 때문에 이 글에서 설명하는 SQL Server뿐만 아니라, MySQL, MariaDB 등의 다른 DBMS도 같은 방법으로 사용할 수 있다
ODBC를 코딩하기 전에
데이터 베이스 DSN을 설정해야 한다
DSN은 Data Source Name으로 데이터베이스와 관련된 정보를 DSN 이름을 사용해서 사용할 수 있게 한다
간단하게 데이터베이스와 연결하기 위해 필요한 정보들을 DSN 이름 하나만으로 사용할 수 있다고 생각하면 된다
해당 링크에서 SQL Server ODBC 드라이버를 다운로드 받자
(다른 DBMS를 사용하는 경우 DBMS에 맞는 ODBC 드라이버를 다운로드)

ODBC 데이터 원본 (64비트)를 실행해

드라이버를 선택하고 마침을 누른다

이름에 사용할 DSN을 입력하고
서버에 IPv4 서버 주소를 입력한다

아이디와 비밀번호를 입력


위와 같이 설정해주고

테스트 했을 때 테스트 성공이 나와야된다
이제 간단한 코드로 MFC 다이얼로그의 리스트 박스 안에 데이터베이스 내용을 출력해보자
프로젝트는 대화 형식 기반으로 생성했다

다이얼로그에 리스트박스와 데이터를 가져오는 버튼까지 넣자

리스트 박스 변수를 추가해주고

클래스 마법사로 함수를 생성한다

다이얼로그 헤더파일에 ODBC를 사용하기 위한 헤더 파일과 관련 멤버 변수를 추가한다
#include <odbcinst.h>
#include <sqlext.h>
SQLHANDLE mh_environment; // ODBC 기술을 사용하기 위한 환경 정보
SQLHDBC mh_odbc; // ODBC 함수를 사용하기 위한 정보
char m_connect_flag = 0; // 서버와 연결 여부를 저장할 변수 (1 : 연결)

다이얼로그 소스 파일에 odbc32.lib 라이브러리 파일도 추가한다
// TODO: 여기에 추가 초기화 작업을 추가합니다.
// ODBC 드라이버에 연결을 위한 기본 정보 설정
SQLSetEnvAttr(NULL, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_DRIVER, SQL_IS_INTEGER);
// ODBC 기술을 사용하기 위한 환경을 구성
// 구성된 환경 정보에 대한 핸들 값은 mh_environment에 저장
if (SQL_ERROR != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &mh_environment))
{
// 사용할 ODBC 버전 정보를 설정
SQLSetEnvAttr(mh_environment, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
SQLSetEnvAttr(mh_environment, SQL_ATTR_CP_MATCH, (SQLPOINTER)SQL_CP_RELAXED_MATCH, SQL_IS_INTEGER);
// ODBC 함수를 사용하기 위한 정보를 구성
// 이 정보에 대한 핸들 값은 mh_odbc에 저장
if (SQL_ERROR != SQLAllocHandle(SQL_HANDLE_DBC, mh_environment, &mh_odbc))
{
RETCODE ret_code = SQLConnect(mh_odbc,
// 접속할 DSN 설정
(SQLWCHAR*)L"test", SQL_NTS,
// 접속에 사용할 ID
(SQLWCHAR*)L"vsUser", SQL_NTS,
// 접속에 사용할 PW
(SQLWCHAR*)L"*******", SQL_NTS);
if (ret_code == SQL_SUCCESS || ret_code == SQL_SUCCESS_WITH_INFO)
{
// ODBC를 사용하여 DB 서버에 성공적으로 접속한 경우
m_connect_flag = 1;
printf("db connect\n");
return 1;
}
else
{
// 접속에 실패한 경우, 구성했던 메모리 제거
if (mh_odbc != SQL_NULL_HDBC) SQLFreeHandle(SQL_HANDLE_DBC, mh_odbc);
if (mh_environment != SQL_NULL_HENV) SQLFreeHandle(SQL_HANDLE_ENV, mh_environment);
}
}
}
다이얼로그 소스 파일의 OnInitDialog() 함수에 상기 코드를 작성해서 프로그램이 실행되면 자동으로 DB와 연결되게 하였다
20번부터 24번 라인까지 본인이 설정한 정보로 작성

서버 연결에 실패했을 때 작동할 함수를 작성하자
클래스 마법사에서 위와 같이 함수를 생성하고
void Ct1Dlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
// 서버에 연결되어 있는 경우에만 제거
// 서버 연결을 실패했다면 실패한 시점에서 아래의 정보가 정리되었기 때문
if (m_connect_flag == 1)
{
if (mh_odbc != SQL_NULL_HDBC) SQLFreeHandle(SQL_HANDLE_DBC, mh_odbc);
if (mh_odbc != SQL_NULL_HENV) SQLFreeHandle(SQL_HANDLE_ENV, mh_environment);
}
}
생성된 함수에 위와 같이 코드를 작성한다
// 데이터를 가져오는 최대 단위 설정
#define MAX_COUNT 100
// 테이블에 저장된 데이터 한 개를 저장할 구조체를 구성
// 크기와 순서가 일치할 필요는 없음
struct UserData
{
wchar_t id[20];
wchar_t name[20];
wchar_t addr[20];
};
void Ct1Dlg::OnClickedButton1()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
// ListBox에 저장된 항목들을 모두 제거
m_List.ResetContent();
// 'meberTBL' 테이블에 저장된 데이터를 모두 읽을 SQL 명령문
wchar_t query_str[256] = L"SELECT * FROM memberTBL";
// 읽어온 데이터의 상태를 기록할 변수
unsigned short record_state[MAX_COUNT];
// 읽어온 데이터를 저장할 변수
UserData raw_data[MAX_COUNT];
CString str;
// 데이터를 저장할 배열 초기화
memset(raw_data, 0, sizeof(raw_data));
HSTMT h_statement;
RETCODE ret_code;
// Query 문을 위한 메모리 할당
if (SQL_SUCCESS == SQLAllocHandle(SQL_HANDLE_STMT, mh_odbc, &h_statement))
{
printf("In Query\n");
// 읽은 데이터의 개수를 저장할 변수
unsigned long record_num = 0;
// Query 문을 실행할 때 타임 아웃을 설정
SQLSetStmtAttr(h_statement, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER)15, SQL_IS_UINTEGER);
// 가져온 데이터를 저장할 메모리 크기를 설정
SQLSetStmtAttr(h_statement, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(raw_data), 0);
// 데이터를 가져올 때 동시성에 대한 방식 설정
SQLSetStmtAttr(h_statement, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, SQL_IS_UINTEGER);
// 검색된 데이터의 위치를 기억하는 방식 설정
SQLSetStmtAttr(h_statement, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, SQL_IS_UINTEGER);
// 데이터를 가져오는 최대 단위를 설정
SQLSetStmtAttr(h_statement, SQL_ATTR_ROW_NUMBER, (SQLPOINTER)MAX_COUNT, SQL_IS_UINTEGER);
// 읽은 데이터의 상태를 저장할 변수의 주소를 전달
SQLSetStmtAttr(h_statement, SQL_ATTR_ROW_STATUS_PTR, record_state, 0);
// 읽은 데이터의 개수를 저장할 변수의 주소 전달
SQLSetStmtAttr(h_statement, SQL_ATTR_ROWS_FETCHED_PTR, &record_num, 0);
printf("#read data : %d\n", record_num);
// 테이블에서 가져온 데이터를 속성별로 raw_data 변수에 저장하기 위해 속성별로 저장할 메모리의 위치 설정
SQLBindCol(h_statement, 1, SQL_WCHAR, raw_data[0].id, sizeof(wchar_t) * 20, NULL);
SQLBindCol(h_statement, 2, SQL_WCHAR, raw_data[0].name, sizeof(wchar_t) * 20, NULL);
SQLBindCol(h_statement, 3, SQL_WCHAR, raw_data[0].addr, sizeof(wchar_t) * 20, NULL);
// SQL 명령문을 실행
ret_code = SQLExecDirect(h_statement, (SQLWCHAR*)query_str, SQL_NTS);
// SQL 명령문의 실행 결과로 받은 데이터를 List Box에 추가
while (ret_code = SQLFetchScroll(h_statement, SQL_FETCH_NEXT, 0) != SQL_NO_DATA)
{
// 데이터 개수만큼 반복하면서 작업
for (unsigned int i = 0; i < record_num; i++)
{
// 가져온 데이터가 삭제된 정보가 아니라면 해당 속성으로 합쳐서 문자열로 구성하고 ListBox에 등록
if (record_state[i] != SQL_ROW_DELETED && record_state[i] != SQL_ROW_ERROR)
{
str.Format(L"%s, %s, %s", raw_data[i].id, raw_data[i].name, raw_data[i].addr);
m_List.InsertString(-1, str);
}
}
}
// Query 문을 위해 할당한 메모리 해제
SQLFreeHandle(SQL_HANDLE_STMT, h_statement);
}
}
다이얼로그 소스 파일의 버튼 클릭 함수에 위와 같이 코드를 작성한다

프로그램을 실행하고 버튼을 클릭하면 해당 오류가 발생할 수 있는데
계속을 누르면

잘 뜬다
여기까지 잘 수행했으면, 매번 쿼리로 DB에서 데이터를 가져올 때마다 위와 같이 긴 코드를 작성해야 하는가 생각할 수 도 있는데, 실제로는 해당 코드들을 클래스화해서 사용한다고 한다
다음에 시간이 된다면 클래스화해서 사용하는 코드 또 올릴지도?
'CS > DB' 카테고리의 다른 글
| [MySQL] python과 C, C++로 MySQL 연동하기 (0) | 2024.02.23 |
|---|---|
| [MySQL] 초기 접속, 비밀번호 변경, DB · TABLE 생성, CRUD (0) | 2024.02.22 |
| 데이터베이스 기초 (1) | 2024.02.13 |
| [ODBC, 비주얼 스튜디오, SQL Server] 데이터 삽입, 삭제 (0) | 2023.11.05 |
| [SQL Server] 설치 & 사용 (0) | 2023.11.04 |