MySQL C API를 사용한 이미지 데이터 삽입 및 조회

기본 데이터 삽입 절차

MySQL C API를 통해 데이터베이스에 일반적인 데이터를 삽입하는 과정은 다음과 같습니다:

  1. 데이터베이스 핸들 초기화: init 함수 호출
  2. 데이터베이스 연결: real_connect 함수 사용
  3. SQL 쿼리 실행: real_query 함수로 명령 전달
  4. 연결 종료: close 함수 호출

핵심 함수 설명

핸들 초기화

mysql_init(MYSQL *mysql)

데이터베이스 연결

MYSQL *
mysql_real_connect(MYSQL *mysql,
                  const char *host,        
                  const char *user,        
                  const char *passwd,      
                  const char *db,          
                  unsigned int port,       
                  const char *unix_socket, 
                  unsigned long client_flag)

연결 실패 시 NULL 반환, 성공 시 첫 번째 매개변수와 동일한 값 반환.

쿼리 실행

int
mysql_real_query(MYSQL *mysql,
                const char *stmt_str,     
                unsigned long length)     

연결 종료

void
mysql_close(MYSQL *mysql)

실제 구현 예시

#include <mysql.h>
#include <stdio.h>
#include <string.h>

#define SERVER_PORT    3306
#define SERVER_IP      "192.168.189.128"
#define USERNAME       "admin"
#define PASSWORD       "197523@cyr"
#define DATABASE_NAME  "YU_DB"
#define INSERT_QUERY   "INSERT TBL_USER(U_NAME, U_GENGDER) VALUES('yu', 'woman');"

int main(){
    MYSQL connection;
    
    if(NULL == mysql_init(&connection)){
        printf("초기화 오류: %s\n",mysql_error(&connection));
        return -1;
    }
 
    if(!mysql_real_connect(&connection,SERVER_IP,USERNAME,PASSWORD,DATABASE_NAME,SERVER_PORT, NULL,0)){
        printf("연결 오류: %s\n",mysql_error(&connection));
    }
 
    if(mysql_real_query(&connection,INSERT_QUERY,strlen(INSERT_QUERY))){
        printf("쿼리 실행 오류: %s\n",mysql_error(&connection));
    }
    
    mysql_close(&connection);
    return 0;
}

이미지 데이터 처리 방법

데이터 타입 선택

이미지와 같은 바이너리 대용량 객체는 BLOB(Binary Large Object) 타입으로 저장합니다. MySQL에서 제공하는 BLOB 타입은 다음과 같습니다:

  • TINYBLOB
  • BLOB
  • MEDIUMBLOB
  • LONGBLOB

테이블 구조 변경 예시:

ALTER TABLE TBL_USER ADD U_IMAGE LONGBLOB;
ALTER TABLE TBL_USER MODIFY U_IMG LONGBLOB;

PreparedStatement 활용

바이너리 데이터 처리를 위해 PreparedStatement 방식을 사용합니다. 이 방식의 장점은 다음과 같습니다:

  • 쿼리 파싱을 한 번만 수행하여 성능 향상
  • 네트워크 트래픽 감소
  • 바이너리 프로토콜 사용으로 효율적인 데이터 전송

이미지 삽입 절차

  1. Statement 핸들 초기화: init과 prepare
  2. 파라미터 바인딩: bind_param
  3. 데이터 전송: send_long_data
  4. 쿼리 실행: execute
  5. 핸들 종료: close

구현 코드

쿼리 준비

INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('King', 'man', ?)

핸들 초기화

MYSQL_STMT *
mysql_stmt_init(MYSQL *mysql)

int
mysql_stmt_prepare(MYSQL_STMT *stmt,
                  const char *stmt_str,    
                  unsigned long length)    

파라미터 설정

MYSQL_BIND param = {0}; 
param.buffer_type = MYSQL_TYPE_LONG_BLOB;   
param.buffer = NULL;                        
param.is_null = 0;                          
param.length = NULL;                        

파라미터 바인딩

bool
mysql_stmt_bind_param(MYSQL_STMT *stmt,
                     MYSQL_BIND *bind)

데이터 전송

bool
mysql_stmt_send_long_data(MYSQL_STMT *stmt,
                         unsigned int parameter_number,    
                         const char *data,                 
                         unsigned long length)             

실행 및 종료

int mysql_stmt_execute(MYSQL_STMT *stmt)
bool mysql_stmt_close(MYSQL_STMT *stmt)

이미지 조회 절차

  1. Statement 핸들 초기화
  2. 결과셋 바인딩
  3. 쿼리 실행
  4. 결과 캐싱 및 데이터 추출
  5. 핸들 종료

조회 구현 예시

int mysql_read_image(MYSQL* conn, char* buffer, int length){
    if(conn == NULL || buffer == NULL || length <= 0) return -1;
    
    MYSQL_STMT* stmt = mysql_stmt_init(conn);
    int ret = mysql_stmt_prepare(stmt, SELECT_QUERY, strlen(SELECT_QUERY));
    if(ret){
        printf("준비 오류: %s\n", mysql_error(conn));
        return -2;
    } 

    MYSQL_BIND result = {0};
    result.buffer_type = MYSQL_TYPE_LONG_BLOB;
    unsigned long total_length = 0;
    result.length = &total_length;

    ret = mysql_stmt_bind_result(stmt, &result);
    if(ret){
        printf("결과 바인딩 오류: %s\n",mysql_error(conn));
        return -3;
    }

    ret = mysql_stmt_execute(stmt);
    if(ret){
        printf("실행 오류: %s\n",mysql_error(conn));
        return -4;
    }

    ret = mysql_stmt_store_result(stmt);
    if(ret){
        printf("결과 저장 오류: %s\n",mysql_error(conn));
        return -5;
    }
    
    while(1){
        ret = mysql_stmt_fetch(stmt);
        if(ret != 0 && ret != MYSQL_DATA_TRUNCATED)break;

        int offset = 0;
        while(offset < (int)total_length){
            result.buffer = buffer + offset; 
            result.buffer_length = 1;
            mysql_stmt_fetch_column(stmt,&result, 0, offset);
            offset += result.buffer_length;
        }
    }

    ret = mysql_stmt_close(stmt);
    if(ret){
        printf("종료 오류: %s\n", mysql_error(conn));
        return -6;
    }
    return total_length;
}

주요 함수 상세 설명

mysql_stmt_execute()

PreparedStatement와 관련된 쿼리를 실행합니다. 바인딩된 파라미터 값을 서버로 전송하고, 새로운 데이터로 치환합니다.

반환값: 성공 시 0, 오류 발생 시 비0값

mysql_stmt_send_long_data()

대용량 파라미터 데이터를 분할하여 서버로 전송합니다. mysql_stmt_bind_param() 이후, mysql_stmt_execute() 이전에 호출해야 합니다.

bool
mysql_stmt_send_long_data(MYSQL_STMT *stmt,                
                         unsigned int parameter_number,    
                         const char *data,                 
                         unsigned long length)             

절차별 비교 요약

직접 실행 PreparedStatement 삽입 PreparedStatement 조회
init → real_connect → real_query → close init/prepare → bind_param → send_long_data → execute → close init/prepare → bind_result → execute → store_result/fetch/fetch_column → close

태그: MySQL C API BLOB PreparedStatement Database Connection

10월 5일 23:17에 게시됨