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 }
);
이 예시에서는 category
와 price
라는 이름으로 명명된 플레이스홀더를 사용하였고, 대응하는 값은 { category: 'electronics', price: 100 }
객체로 전달되었습니다. 이렇게 작성된 쿼리는 읽기 쉽고 관리하기 용이합니다.
4. 주의사항 및 한계
명명된 플레이스홀더는 매우 유용하지만, 몇 가지 주의해야 할 점이 있습니다.
(1) 콜론으로 시작하는 플레이스홀더
명명된 플레이스홀더는 항상 콜론(:
)으로 시작하며, 그 뒤에는 해당 파라미터를 식별할 수 있는 이름이 따라와야 합니다. 예를 들어 :userId
, :status
와 같은 형태로 작성됩니다.
(2) 파라미터 객체의 키 이름
쿼리를 실행할 때 파라미터로 전달하는 객체의 키 이름은 쿼리에서 사용하는 플레이스홀더 이름과 정확히 일치해야 합니다. 예를 들어, :userId
라는 플레이스홀더를 사용했다면 객체에서 userId
라는 키를 포함해야 합니다.
(3) 지원되는 메서드
명명된 플레이스홀더는 MySQL2의 query
및 execute
메서드에서만 지원됩니다. prepare
, mysql.format
, 또는 Pool.format
에서는 명명된 플레이스홀더를 사용할 수 없습니다. 따라서 쿼리 성능 최적화를 위해 prepare
를 사용하는 경우에는 unnamed 플레이스홀더(?
)만 사용할 수 있다는 점을 유의해야 합니다.
(4) 내부 동작
MySQL 프로토콜 자체는 명명된 파라미터를 지원하지 않습니다. 따라서 MySQL2 라이브러리는 내부적으로 명명된 플레이스홀더를 unnamed 플레이스홀더(?
)로 변환한 뒤 쿼리를 실행합니다. 이는 성능에 큰 영향을 미치지 않지만, 프로토콜 차원의 지원이 아니라는 점에서 이해하고 사용할 필요가 있습니다.
5. 명명된 플레이스홀더의 장점
명명된 플레이스홀더는 특히 복잡한 쿼리에서 큰 장점을 제공합니다.
(1) 가독성 향상
명명된 플레이스홀더를 사용하면 각 파라미터의 의미가 코드에 명확하게 드러나므로, 쿼리 가독성이 크게 향상됩니다. 예를 들어 ?
를 사용하는 쿼리에서는 파라미터의 순서가 중요하며, 이를 실수로 혼동할 수 있지만, 명명된 플레이스홀더를 사용하면 이러한 위험을 줄일 수 있습니다.
(2) 유지보수성 강화
쿼리에서 파라미터를 추가하거나 수정할 때, unnamed 플레이스홀더는 모든 파라미터의 순서를 유지해야 하지만, 명명된 플레이스홀더를 사용하면 파라미터 순서에 상관없이 이름만 맞추면 되므로 유지보수가 더 쉬워집니다.
(3) 안전성 강화
명명된 플레이스홀더를 사용하면 파라미터를 명확하게 구분할 수 있어 실수로 인한 잘못된 데이터 입력을 방지할 수 있습니다. 이는 특히 여러 곳에서 같은 파라미터를 사용하는 경우 유용합니다.
6. 결론
MySQL2에서 명명된 플레이스홀더를 사용하면 쿼리의 가독성 및 유지보수성을 높일 수 있으며, 복잡한 쿼리에서 특히 유용합니다. 이 기능을 활용하면 코드의 안정성과 가독성을 동시에 확보할 수 있으며, 다양한 상황에서 더 효율적으로 데이터베이스 쿼리를 작성할 수 있습니다.
참조
'JavaScript & TypeScript' 카테고리의 다른 글
JavaScript - join() 함수 소개 (0) | 2024.10.04 |
---|---|
npm mysql2 라이브러리에서 query와 execute 메서드 비교 (1) | 2024.10.03 |
TypeScript에서 `??`와 `||`의 차이: 상세한 설명과 사용 예시 (0) | 2024.09.19 |
TypeScript에서 `==` 와 `===` 의 차이점 및 적절한 사용법 (0) | 2024.09.19 |
npm options --save (0) | 2022.05.02 |