본문 바로가기
컴퓨터/Server

DB 연동하기

by 김짱쌤 2015. 5. 9.

ODBC

ODBC는 윈도우에서 정해진 데이터베이스에 접근하는 표준 규격이다. ODBC는 SQL 표준 인터페이스에 근간을 두고 서로다른 데이터 베이스에 맞는 요청으로 자동 변환하여 사용할 수 있게 만들어 준다. 따라서 서로 다른 데이터 베이스의 API를 몰라도 ODBC 인터페이스에서 정해진 방식만 따라가면 그 데이터 베이스를 사용할 수 있다. 이를 위해 각 DB별로 별도의 모듈 및 드라이버가 필요하다. 대부분의 DBMS들이 ODBC를 지원하기 위한 드라이버를 제공하고 있다.

ODBC에 DB 등록하기

ODBC로 데이터베이스에 접근하기 위해서는, 사용하고자 하는 DBMS를 ODBC관리자에서 추가한 뒤에 사용해야 한다. 자세한 내용은 링크

ODBC 준비하기

DB에 연결하기 위해서 먼저 ODBC에 사용되는 핸들을 생성해야 한다.

SQL_HANDLE_ENV  - ENVIRONMENT 환경 핸들
SQL_HANDLE_DBC  - CONNECTION 연결 핸들
SQL_HANDLE_STMT – STATEMENT 명령문 핸들
SQL_HANDLE_DESC – DESCRIPTOR 표현 핸들
  • ODBC 핸들 할당받기
SQLRETURN SQLAllocHandle( //핸들 할당하는 함수
    SQLSMALLINT HandleType, //핸들의 타입
    SQLHANDLE InputHandle,  //새로 만들어질 핸들의 부모 핸들
    SQLHANDLE* OutputHandlePtr //핸들을 저장할 핸들변수
); 
  • DB 연결 : 생성된 핸들을 가지고 디비에 접속한다.
SQLRETURN SQLDriverConnect(
        SQLHDBC         ConnectionHandle,      // DB 연결 핸들
        SQLHWND         WindowHandle,         // 윈도우 핸들 (사용안함)
        SQLCHAR *       InConnectionString,     // 연결 디비 이름
        SQLSMALLINT     StringLength1,          // 연결 문자열의 길이
        SQLCHAR *       OutConnectionString,    //   ID
        SQLSMALLINT     BufferLength,           //   연결 완료된 문자열의 크기 
        SQLCHAR *       OutConnectionString,    //   PW
        SQLSMALLINT *   StringLength2Ptr,       //   연결 완료된 문자열의 길이         
        SQLUSMALLINT    DriverCompletion       // 연결 옵션
);

DB 명령어 실행하기

  1. 쿼리 실행하기

  • SQLBindParameter : 생성된 명령문 핸들에 받을 데이터 형식(속성, 값 저장 변수 등)을 바인딩한다.
SQLRETURN SQLBindParameter(
      SQLHSTMT        StatementHandle,  //명령문 핸들
      SQLUSMALLINT    ParameterNumber,  //매개변수 마커 번호
      SQLSMALLINT     InputOutputType,  //매개변수 입력 타입
      SQLSMALLINT     ValueType,        //매개변수 C 타입
      SQLSMALLINT     ParameterType,    //매개변수 SQL 타입
      SQLULEN         ColumnSize,       //매개변수의 정밀도
      SQLSMALLINT     DecimalDigits,    //자릿수 표현
      SQLPOINTER      ParameterValuePtr,//매개변수로 넘길(받을) 데이터 포인터
      SQLLEN          BufferLength,     //사용되지 않음
      SQLLEN *        StrLen_or_IndPtr  //데이터의 길이
);

  • SQLExecDirect : 쿼리 문자열을 날려서 DB요청한다.
SQLRETURN SQLExecDirect(
        SQLHSTMT        StatementHandle,        // SQL 명령문 핸들
        SQLCHAR *       StatementText,          // 실행될 SQL 문
        SQLINTEGER      TextLength              // 실행될 SQL 문의 길이
); 

  1. 쿼리 결과값 받기
  • SQLBindCol : 받을 인자를 미리 지정한다.
SQLRETURN SQLBindCol(
        SQLHSTMT     StatementHandle,  // SQL 명령문 핸들
        SQLUSMALLINT ColumnNumber,     // 열 값의 순서 (1부터 시작)
        SQLSMALLINT  TargetType,       // 열 값의 데이터형 (C Data Type)
        SQLPOINTER   TargetValuePtr,   // 바인딩될 변수
        SQLINTEGER   BufferLength,     // 바인딩될 변수의 크기       
        SQLLEN *     StrLen_or_Ind     // 열 값의 길이OR상태값을 반환 받을 변수
); 
  • SQLFetch : 명령문 핸들에서 결과값 받아온다.
SQLRETURN SQLFetch( 
        SQLHSTMT        StatementHandle         // SQL 명령문 핸들
);

연결 종료

  1. 명령문 핸들 종료, 할당 해제
  2. 연결 핸들을 끊고 할당 해제
  3. 다른 핸들 할당 해제
  4. 순서대로 실행 코드
SQLCloseCursor( hStmt );                        // STEP 1
SQLFreeHandle( SQL_HANDLE_STMT, hStmt );        // STEP 2
SQLDisconnect( hDBC );                          // STEP 3
SQLFreeHandle( SQL_HANDLE_DBC, hDBC );          // STEP 4
SQLFreeHandle( SQL_HANDLE_ENV, hENV );

DB와 연동하는 다른 대안들

ADO (ActiveX Data Object)

ADO는 ODBC에 접근하기 위해 마이크로소프트에서 표준으로 제작된 컴포넌트 오브젝트 모델 객체/API들의 집합을 말한다. 프로그래밍 언어와 ODBC사이에 원활한 접근을 위해 만들어진 객체 지향형 인터페이스라고 생각하면 될듯. 사용자는 SQL또는 ODBC 접근 방식을 잘 몰라도 좀 더 간단하게 DB에 요청을 날릴 수 있다.

ADO 객체들은 Connection 객체, Recordset 객체, Command객체로 구성된다.

  • Connection 객체 : DB에 연결하기 위해서 사용되는 것처럼 보이지만, 실상은 여러 요청을 날릴 수도 있다. Insert, Update, Delete, Select가 가능하다.
  • Command 객체 : ADO 중급 수준이상부터 사용된다고 한다. SP사용에 편리한 parameter 속성을 사용할 수 있으며, 명령에 timer를 적용하여 잠시 대기시키는 명령등, 고급 옵션들이 추가된다.
  • Recordset 객체 : 요청한 명령의 결과(record)를 받아서 읽을 수 있도록 도와주는 객체이다. record pointer 개념을 도입하여 간편하게 결과 record들을 읽어 올 수 있다.

ORM (Object-Relation Mapping)

이름 그대로 OOP의 객체와 DB의 relation을 매핑해주는 역할을 한다. DB의 entity들은 테이블(relation)형식으로 구성된다. OOP의 객체들은 데이터 멤버 또는 또다른 멤버 객체를 들고 있는 형식으로 구성된다. OOP에서 DB를 연동할때 이 차이점은 불편하게 다가올 수 있다. ORM은 그 간격을 메꿔주는 Layer역할을 한다. 우리는 ORM을 사용하여 OOP의 룰 아래에서 형식이 다른 DB의 relation을 mapping한 객체를 받아 사용할 수 있다.

매핑하는 방식은 크게 one-to-one/ subset/ superset mapping으로 분류할 수 있다.

  • one-to-one mapping : 테이블의 한 row를 하나의 객체 instance로 매핑시켜준다.
  • subset mapping : 하나의 테이블을 여러개의 class로 분류하여 매핑시켜준다. (ex: Person테이블을 각 속성에 따라 나누어 Employee와 Customer로 나누어 매핑)
  • superset mapping : 여러개의 테이블을 하나의 class로 묶어서 매핑시켜준다. (ex: Person테이블과 PersonInfo 테이블을 합성하여 Person객체로 통합하여 매핑)


HSHA (Half Sync Half Async)

앞에서 언급했지만 DB작업도 분명한 I/O작업이다. DB의 도움을 받지 않는 비지니스 서버는 흔치 않다. 그러면 DB서버와의 I/O작업은 어떻게 처리해야될 것인가? IOCP등의 비동기 서버를 돌린다면 DB의 I/O를 별도로 처리한다는 것은 골치아픈일이 될 것이다. 이때 도움을 받을 수 있는 것이 바로 HSHA패턴이다.

http://egloos.zum.com/javawork/v/1818696

HSHA패턴은 이름 그대로 네트워크 처리는 Async방식으로 진행하고, DB및 기타 데이터처리는 Sync방식으로 처리하는 것이다. 서로 다른 동기화 방식의 TASK 레이어가 있고, 두 레이어는 Message Queue를 통해 서로 통신한다. IOCP를 쓴다면 IOCP의 worker thread가 Async TASK Layer가 될 것이고, DB를 처리하는 DB Thread가 Sync TASK Layer가 될 것이다. IOCP를 통해 작업을 진행하다가 DB작업이 필요하면 Message Queue에 필요한 작업을 push하고, DB 쓰레드는 Message Queue를 Listen한 상태에서 Message에 작업이 들어오면 동기적으로 작업을 처리한다.

HSHA를 적용하면 데이터 또는 로직을 담당하는 레이어를 동기방식으로 동작하게 함으로써, 비동기 구현의 복잡하고 어려운 이슈들을 피할 수 있다. 실제로 성능이 필요한 부분에만 비동기 멀티쓰레드 작업을 진행하고, 그렇지 않은 부분은 간단한 동기적 프로그래밍을 통하여 구현하므로 보다 나은 작업 효율을 기대할 수 있다. 그리고 두 레이어간 접근은 오직 Message를 통한 통신뿐이므로, 독립적으로 커플링이 발생하지 않게 구현할 수 있다. 대신 레이어간 데이터가 이동할 때 오버헤드가 발생할 수 있다. Message Queue를 동기화하여 데이터를 복사하는 작업이 비동기 레이어 수준에서는 오버헤드를 발생시킬 수 있기 때문이다.

'컴퓨터 > Server' 카테고리의 다른 글

Exception Filter  (1) 2015.05.15
Stored Procedures  (0) 2015.05.09
멀티쓰레드 서버 버그잡기  (0) 2015.05.04
Lock Free  (2) 2015.04.28
Thread Local Storage  (0) 2015.04.26