회원가입 | 고객센터 |
DESIGNONEX
디자인원엑스
About
Service
PR리그N
Q&AN
노하우
공지사항N
통계
로그인 회원가입
고객센터
14. 데이터베이스

Database 직접 쿼리 개발

A Administrator
2026.05.19 18:15(수정됨) 24 0

1. 시작하기 — DB 인스턴스 얻기

DXCMS의 모든 DB 작업은 Database 싱글턴 클래스를 통해 이루어집니다. 어떤 PHP 파일(페이지, 스킨, 플러그인)에서든 아래 한 줄로 시작합니다.
$db = Database::getInstance();

// 테이블명 생성 — prefix(dx_) 자동 포함
$tbl = $db->table('posts');         // => "dx_posts"
$tbl = $db->table('members');       // => "dx_members"
$tbl = $db->table('studio_posts');  // => "dx_studio_posts"

※ 반드시 $db->table()을 사용하세요. 테이블명을 하드코딩하면 prefix 변경 시 모두 수정해야 합니다


2. BIGINT ID 핵심 주의사항

DXCMS는 posts, comments 등의 PK를 microtime 기반 16자리 BIGINT로 생성합니다. PHP 32bit 환경에서 (int) 캐스팅하면 값이 손상됩니다.
// ❌ 절대 금지 — 32bit PHP에서 값이 잘림
$id = (int)$_p['id'];                    // 1778651007020800 → 손상
$map[(int)$row['post_id']] = $row;       // 키 손상

// ✓ 올바른 방법 — 문자열로 처리
$id = (string)$_p['id'];                 // "1778651007020800" 유지
$map[(string)$row['post_id']] = $row;    // 키 정확히 저장

// 쿼리 바인딩은 문자열 그대로 전달
$db->row("SELECT * FROM `{$tbl}` WHERE id = ?", array($id));

※ PDO 설정에 ATTR_STRINGIFY_FETCHES=true 가 있어 DB에서 받은 값은 이미 문자열입니다. PHP 코드에서 (int) 캐스팅만 하지 않으면 됩니다.


3. SELECT — 데이터 조회


3-1. row() — 단일 행 조회

조건에 맞는 첫 번째 행을 연관 배열로 반환합니다. 결과 없으면 null 반환.
$db  = Database::getInstance();
$tbl = $db->table('members');

$member = $db->row(
    "SELECT * FROM `{$tbl}` WHERE id = ? AND status = 1",
    array($memberId)
);

if ($member) {
    echo $member['name'];
    echo $member['email'];
}


3-2. rows() — 여러 행 조회

조건에 맞는 모든 행을 2차원 배열로 반환합니다. 결과 없으면 빈 배열 반환.
$db  = Database::getInstance();
$tbl = $db->table('posts');

$posts = $db->rows(
    "SELECT id, title, created_at
     FROM `{$tbl}`
     WHERE board_id = ? AND status = 1
     ORDER BY id DESC LIMIT ?",
    array($boardId, 10)
);

foreach ($posts as $p) {
    echo $p['title'];
}


3-3. value() — 단일 값 조회

COUNT, SUM 등 집계 함수나 컬럼 하나의 값만 필요할 때 사용합니다.
$db  = Database::getInstance();
$tbl = $db->table('members');

// 회원 수
$count = $db->value("SELECT COUNT(*) FROM `{$tbl}` WHERE status = 1");

// 특정 회원의 포인트
$point = $db->value(
    "SELECT point FROM `{$tbl}` WHERE id = ?",
    array($memberId)
);


3-4. find() — 편의 메서드 (단일 행)

SQL 없이 조건 배열로 단일 행을 조회합니다.
$db = Database::getInstance();

// 기본
$member = $db->find('members', array('id' => $memberId));

// 반환 컬럼 지정
$member = $db->find(
    'members',
    array('email' => $email, 'status' => 1),
    'id, name, email'
);


3-5. findAll() — 편의 메서드 (여러 행)

SQL 없이 조건 배열로 여러 행을 조회합니다. 정렬과 LIMIT도 지정 가능합니다.
$db = Database::getInstance();

$rows = $db->findAll(
    'posts',                                        // 테이블명
    array('board_id' => $boardId, 'status' => 1),  // WHERE
    'id, title, created_at',                        // 반환 컬럼
    'id DESC',                                      // ORDER BY
    '10'                                            // LIMIT
);


3-6. IN 절 — 여러 ID 한 번에 조회

복수 ID를 한 번의 쿼리로 조회할 때 IN 절을 사용합니다. BIGINT ID는 반드시 문자열로 처리합니다.
$db  = Database::getInstance();
$tbl = $db->table('studio_posts');

// ID 배열 — 문자열 유지
$ids = array('1778651007020800', '1778766294011100');

// IN 절 플레이스홀더 생성
$ph = implode(',', array_fill(0, count($ids), '?'));

// 쿼리
$rows = $db->rows(
    "SELECT post_id, youtube_url FROM `{$tbl}` WHERE post_id IN ({$ph})",
    $ids
);

// string 키로 맵 생성 — (int) 절대 금지
$map = array();
foreach ($rows as $r) {
    $map[(string)$r['post_id']] = $r;
}

// 사용
$info = isset($map[(string)$postId]) ? $map[(string)$postId] : array();


4. INSERT — 데이터 추가


4-1. insertRow() — 편의 메서드

컬럼 => 값 배열을 전달하면 INSERT SQL을 자동 생성합니다. AUTO_INCREMENT PK 테이블에 사용합니다.
$db = Database::getInstance();

$db->insertRow('download_log', array(
    'file_id'    => $fileId,
    'member_id'  => $memberId,
    'ip'         => dx_ip(),
    'point_used' => 0,
    'created_at' => date('Y-m-d H:i:s'),
));

// 반환값: 마지막 AUTO_INCREMENT ID
$newId = $db->insertRow('categories', array(
    'name'       => '공지사항',
    'sort_order' => 1,
    'created_at' => date('Y-m-d H:i:s'),
));


4-2. insertWithMicrotimeId() — BIGINT ID 자동 생성

posts, comments 등 microtime 기반 BIGINT PK 테이블에 삽입합니다. ID를 자동 생성하고 중복 검사 후 삽입합니다.
$db = Database::getInstance();

$postId = $db->insertWithMicrotimeId('posts', array(
    'board_id'   => $boardId,
    'member_id'  => $memberId,
    'title'      => '제목',
    'content'    => '내용',
    'status'     => 1,
    'created_at' => date('Y-m-d H:i:s'),
    'updated_at' => date('Y-m-d H:i:s'),
));

// 반환값은 문자열 — 절대 (int) 캐스팅 금지
echo $postId; // "1778651007020800"


4-3. insert() / query() — 직접 SQL

INSERT … ON DUPLICATE KEY UPDATE 등 복잡한 구문은 직접 SQL을 작성합니다.
$db  = Database::getInstance();
$tbl = $db->table('studio_posts');
$now = date('Y-m-d H:i:s');

// 직접 INSERT
$db->query(
    "INSERT INTO `{$tbl}`
     (post_id, youtube_url, producer, creator, created_at, updated_at)
     VALUES (?, ?, ?, ?, ?, ?)",
    array($postId, $youtubeUrl, $producer, $creator, $now, $now)
);

// ON DUPLICATE KEY UPDATE (UPSERT)
$db->query(
    "INSERT INTO `{$db->table('settings')}` (setting_key, setting_value)
     VALUES (?, ?)
     ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)",
    array('site_name', 'DXCMS')
);


5. UPDATE — 데이터 수정


5-1. updateRow() — 편의 메서드

수정할 데이터와 WHERE 조건을 각각 배열로 전달합니다. 모든 조건은 AND로 연결됩니다.
$db = Database::getInstance();

// 단일 컬럼 수정
$db->updateRow(
    'members',
    array('point' => $newPoint),   // SET
    array('id'    => $memberId)    // WHERE
);

// 여러 컬럼 수정
$db->updateRow(
    'studio_posts',
    array(
        'youtube_url' => $youtubeUrl,
        'producer'    => $producer,
        'updated_at'  => date('Y-m-d H:i:s'),
    ),
    array('post_id' => $postId)    // BIGINT — 문자열 그대로
);


5-2. query() — 직접 SQL UPDATE

증감 연산(+=, -=), CASE WHEN 등 복잡한 UPDATE는 직접 SQL을 작성합니다.
$db  = Database::getInstance();
$tbl = $db->table('members');

// 포인트 차감 — 조건부 (0 미만 방지)
$db->query(
    "UPDATE `{$tbl}` SET point = point - ? WHERE id = ? AND point >= ?",
    array($dlPoint, $memberId, $dlPoint)
);

// 조회수 +1
$db->query(
    "UPDATE `{$db->table('posts')}` SET view_count = view_count + 1 WHERE id = ?",
    array($postId)
);

// 반환값: 영향받은 행 수
$affected = $db->query(
    "UPDATE `{$tbl}` SET status = 0 WHERE last_login < ?",
    array(date('Y-m-d', strtotime('-1 year')))
);


6. DELETE — 데이터 삭제


6-1. deleteRow() — 편의 메서드

WHERE 조건 배열을 전달하면 DELETE SQL을 자동 생성합니다.
$db = Database::getInstance();

// 단일 행 삭제
$db->deleteRow('studio_posts', array('post_id' => $postId));

// 여러 조건 (AND)
$db->deleteRow(
    'download_log',
    array('member_id' => $memberId, 'file_id' => $fileId)
);


6-2. query() — 직접 SQL DELETE

IN 절이나 복잡한 조건이 필요한 삭제는 직접 SQL을 작성합니다.
$db  = Database::getInstance();
$tbl = $db->table('post_files');

// 게시글 파일 전체 삭제
$db->query(
    "DELETE FROM `{$tbl}` WHERE post_id = ?",
    array($postId)
);

// IN 절 삭제
$ids = array('1778651007020800', '1778766294011100');
$ph  = implode(',', array_fill(0, count($ids), '?'));
$db->query("DELETE FROM `{$tbl}` WHERE id IN ({$ph})", $ids);

// 날짜 조건 삭제
$db->query(
    "DELETE FROM `{$db->table('visit_log')}` WHERE created_at < ?",
    array(date('Y-m-d', strtotime('-30 days')))
);


7. 트랜잭션 — 원자적 처리

여러 쿼리를 하나의 단위로 처리해야 할 때 사용합니다. 오류 발생 시 rollback()으로 모든 변경을 취소합니다.
$db = Database::getInstance();

try {
    $db->begin(); // 트랜잭션 시작

    // 1. 포인트 차감
    $db->query(
        "UPDATE `{$db->table('members')}` SET point = point - ? WHERE id = ?",
        array($price, $memberId)
    );

    // 2. 구매 로그 기록
    $db->insertRow('purchase_log', array(
        'member_id'  => $memberId,
        'item_id'    => $itemId,
        'price'      => $price,
        'created_at' => date('Y-m-d H:i:s'),
    ));

    // 3. 재고 감소
    $db->query(
        "UPDATE `{$db->table('items')}` SET stock = stock - 1 WHERE id = ?",
        array($itemId)
    );

    $db->commit(); // 성공 시 커밋

} catch (Exception $e) {
    $db->rollback(); // 실패 시 전체 롤백
    dx_log('트랜잭션 실패: ' . $e->getMessage(), 'error');
}


8. 기타 편의 메서드


8-1. exists() — 존재 여부

$db = Database::getInstance();

// 이메일 중복 확인
$isDuplicate = $db->exists('members', array('email' => $email));

// 복합 조건
$isOwner = $db->exists('posts', array(
    'id'        => $postId,
    'member_id' => $memberId,
));
8-2. count() — 행 수
$db = Database::getInstance();

$total  = $db->count('members');                         // 전체
$active = $db->count('members', array('status' => 1));  // 조건부
8-3. tableExists() — 테이블 존재 여부
$db = Database::getInstance();

if (!$db->tableExists($db->table('studio_posts'))) {
    $db->query(
        "CREATE TABLE IF NOT EXISTS `{$db->table('studio_posts')}` (
            post_id     BIGINT UNSIGNED NOT NULL,
            youtube_url VARCHAR(500) NOT NULL DEFAULT '',
            PRIMARY KEY (post_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"
    );
}


8-4. escape() — 문자열 이스케이프

$db = Database::getInstance();

// MATCH ... AGAINST 등 플레이스홀더 미지원 구문에만 사용
$kw = $db->escape($userInput);
$db->rows("SELECT * FROM `{$tbl}` WHERE MATCH(title) AGAINST('{$kw}')");

// 일반 쿼리는 반드시 플레이스홀더(?) 사용
$db->row("SELECT * FROM `{$tbl}` WHERE id = ?", array($id));


9. 실전 예제 — studio 데이터 조회

board_latest 스킨 파일 안에서 dx_studio_posts 테이블을 직접 조회하는 실제 코드입니다.
// 1. DB 인스턴스 + 테이블명
$db  = Database::getInstance();
$tbl = $db->table('studio_posts'); // "dx_studio_posts"

// 2. posts 배열에서 ID 수집 — 문자열 유지 필수
$ids = array();
foreach ($posts as $p) {
    if (!empty($p['id'])) $ids[] = $p['id'];
}

// 3. IN 절로 한 번에 조회
$map = array();
if (!empty($ids)) {
    $ph   = implode(',', array_fill(0, count($ids), '?'));
    $rows = $db->rows(
        "SELECT post_id, youtube_url, producer, creator
         FROM `{$tbl}` WHERE post_id IN ({$ph})",
        $ids
    );
    // string 키로 맵 생성 — (int) 절대 금지
    foreach ($rows as $r) {
        $map[(string)$r['post_id']] = $r;
    }
}

// 4. 카드 렌더링에서 사용
foreach ($posts as $p) {
    $row   = isset($map[(string)$p['id']]) ? $map[(string)$p['id']] : array();
    $ytUrl = isset($row['youtube_url']) ? $row['youtube_url'] : '';

    // YouTube ID 추출
    $vidId = '';
    if ($ytUrl && preg_match('/[?&]v=([a-zA-Z0-9_-]{11})/', $ytUrl, $m)) {
        $vidId = $m[1];
    }
    $thumb = $vidId
        ? 'https://img.youtube.com/vi/' . $vidId . '/hqdefault.jpg'
        : '';
}
 

댓글0

로그인 후 댓글을 작성할 수 있습니다.
14. 데이터베이스 Database 직접 쿼리 개발 2026.05.19 14. 데이터베이스 DB스키마 2026.05.12
31
전체 회원
380
전체 게시글
380
전체 댓글
570
오늘 방문
31,687
전체 방문
1
현재 접속
인기글 7일 이내
최신글
최신댓글
목록