본문 바로가기
JavaScript & TypeScript

MySQL2에서 명명된 플레이스홀더(named placeholders) 사용하기

by 대박플머 2024. 10. 3.

Node.js에서 MySQL을 사용하여 데이터베이스 쿼리를 실행할 때, 플레이스홀더를 사용하면 파라미터화된 쿼리를 작성할 수 있어 SQL 인젝션 방지에 큰 도움이 됩니다. MySQL2 라이브러리는 기본적으로 unnamed 플레이스홀더 (?)를 지원하지만, 이를 명명된 플레이스홀더(named placeholders)로 대체하면 가독성이 향상되고 복잡한 쿼리에서 파라미터를 더 쉽게 관리할 수 있습니다. 이번 포스트에서는 MySQL2에서 명명된 플레이스홀더를 설정하고 사용하는 방법을 설명하겠습니다.

1. 명명된 플레이스홀더란?

명명된 플레이스홀더는 쿼리 내에서 파라미터에 고유한 이름을 부여하여, 코드의 가독성을 높이고 실수를 줄이는 데 도움이 됩니다. 예를 들어 SELECT * FROM users WHERE id = ? AND status = ?와 같이 ?를 사용하는 대신, 명명된 플레이스홀더를 사용하면 SELECT * FROM users WHERE id = :userId AND status = :status와 같이 보다 직관적인 쿼리를 작성할 수 있습니다.

명명된 플레이스홀더는 콜론(:)으로 시작하고 그 뒤에 식별자가 이어지며, 쿼리를 실행할 때 식별자에 대응하는 값을 객체로 전달합니다. 이 기능은 복잡한 쿼리에서 특히 유용하며, 값이 여러 번 사용되거나 순서가 중요한 경우 실수를 방지할 수 있습니다.

2. 명명된 플레이스홀더 설정 방법

MySQL2에서 명명된 플레이스홀더를 사용하려면 두 가지 방법이 있습니다. 하나는 데이터베이스 연결 생성 시에 설정하는 방법이고, 다른 하나는 쿼리 실행 시 옵션으로 설정하는 방법입니다.

(1) 연결 생성 시 설정

const mysql = require('mysql2/promise');

const connection = await mysql.createConnection({
  host: 'localhost',
  user: 'root',
  database: 'test',
  namedPlaceholders: true // 명명된 플레이스홀더 사용
});

이처럼 namedPlaceholders: true를 설정하면 해당 연결을 사용하는 모든 쿼리에서 명명된 플레이스홀더를 사용할 수 있습니다.

(2) 쿼리 실행 시 옵션으로 설정

명명된 플레이스홀더를 특정 쿼리에서만 사용하려면, execute 메서드를 호출할 때 옵션으로 설정할 수 있습니다.

const [rows, fields] = await connection.execute(
  'SELECT * FROM users WHERE id = :userId AND status = :status',
  { userId: 1, status: 'active' },
  { namedPlaceholders: true }
);

이렇게 하면 해당 쿼리에서만 명명된 플레이스홀더를 사용할 수 있으며, 다른 쿼리에서는 기본 설정대로 unnamed 플레이스홀더를 사용할 수 있습니다.

3. 명명된 플레이스홀더 사용 예시

명명된 플레이스홀더를 활용하면 쿼리 내 파라미터의 순서를 신경 쓰지 않고, 각 파라미터의 이름만 맞추면 됩니다. 예를 들어, 특정 카테고리의 제품을 검색하면서 가격이 일정 금액 이상인 제품을 찾는 쿼리를 명명된 플레이스홀더로 작성하면 다음과 같습니다.

const [rows, fields] = await connection.execute(
  'SELECT * FROM products WHERE category = :category AND price > :price',
  { category: 'electronics', price: 100 }
);

이 예시에서는 categoryprice라는 이름으로 명명된 플레이스홀더를 사용하였고, 대응하는 값은 { category: 'electronics', price: 100 } 객체로 전달되었습니다. 이렇게 작성된 쿼리는 읽기 쉽고 관리하기 용이합니다.

4. 주의사항 및 한계

명명된 플레이스홀더는 매우 유용하지만, 몇 가지 주의해야 할 점이 있습니다.

(1) 콜론으로 시작하는 플레이스홀더

명명된 플레이스홀더는 항상 콜론(:)으로 시작하며, 그 뒤에는 해당 파라미터를 식별할 수 있는 이름이 따라와야 합니다. 예를 들어 :userId, :status와 같은 형태로 작성됩니다.

(2) 파라미터 객체의 키 이름

쿼리를 실행할 때 파라미터로 전달하는 객체의 키 이름은 쿼리에서 사용하는 플레이스홀더 이름과 정확히 일치해야 합니다. 예를 들어, :userId라는 플레이스홀더를 사용했다면 객체에서 userId라는 키를 포함해야 합니다.

(3) 지원되는 메서드

명명된 플레이스홀더는 MySQL2의 queryexecute 메서드에서만 지원됩니다. prepare, mysql.format, 또는 Pool.format에서는 명명된 플레이스홀더를 사용할 수 없습니다. 따라서 쿼리 성능 최적화를 위해 prepare를 사용하는 경우에는 unnamed 플레이스홀더(?)만 사용할 수 있다는 점을 유의해야 합니다.

(4) 내부 동작

MySQL 프로토콜 자체는 명명된 파라미터를 지원하지 않습니다. 따라서 MySQL2 라이브러리는 내부적으로 명명된 플레이스홀더를 unnamed 플레이스홀더(?)로 변환한 뒤 쿼리를 실행합니다. 이는 성능에 큰 영향을 미치지 않지만, 프로토콜 차원의 지원이 아니라는 점에서 이해하고 사용할 필요가 있습니다.

5. 명명된 플레이스홀더의 장점

명명된 플레이스홀더는 특히 복잡한 쿼리에서 큰 장점을 제공합니다.

(1) 가독성 향상

명명된 플레이스홀더를 사용하면 각 파라미터의 의미가 코드에 명확하게 드러나므로, 쿼리 가독성이 크게 향상됩니다. 예를 들어 ?를 사용하는 쿼리에서는 파라미터의 순서가 중요하며, 이를 실수로 혼동할 수 있지만, 명명된 플레이스홀더를 사용하면 이러한 위험을 줄일 수 있습니다.

(2) 유지보수성 강화

쿼리에서 파라미터를 추가하거나 수정할 때, unnamed 플레이스홀더는 모든 파라미터의 순서를 유지해야 하지만, 명명된 플레이스홀더를 사용하면 파라미터 순서에 상관없이 이름만 맞추면 되므로 유지보수가 더 쉬워집니다.

(3) 안전성 강화

명명된 플레이스홀더를 사용하면 파라미터를 명확하게 구분할 수 있어 실수로 인한 잘못된 데이터 입력을 방지할 수 있습니다. 이는 특히 여러 곳에서 같은 파라미터를 사용하는 경우 유용합니다.

6. 결론

MySQL2에서 명명된 플레이스홀더를 사용하면 쿼리의 가독성 및 유지보수성을 높일 수 있으며, 복잡한 쿼리에서 특히 유용합니다. 이 기능을 활용하면 코드의 안정성과 가독성을 동시에 확보할 수 있으며, 다양한 상황에서 더 효율적으로 데이터베이스 쿼리를 작성할 수 있습니다.

 

참조

https://npmjs.com/package/mysql2/v/0.15.4