SQL 스크립트에서 왜 '?'를 사용할까?
SQL 스크립트에서 왜 ?를 사용할까?
역시 비교봇 / 등록봇 코드를 보다가, ?이 하도 많아서, 기억을 더듬어볼 겸 ?의 사용에 대해 정리를 해보았다.
1. 물음표 기호(?)의 쓰임
- SQL의 '자리 표시자(Placeholder)'로 사용된다.
: SQL 쿼리에서 동적으로 값을 삽입할 때 데이터베이스에 직접 값을 넣는 대신에 ?로 자리를 표시한다.
=> 이후, JavaScript에서 values 배열에 실제 데이터를 채우면 데이터베이스가 이를 바인딩하여 처리한다.
2. 물음표 기호 사용 목적
1) 보안 강화
- SQL 인젝션 방지
: SQL 쿼리에 값을 직접 삽입하면 보안 문제가 발생할 수 있다(ex: SQL 인젝션 공격).
=> ?를 사용하면 값이 안전하게 바인딩되므로 SQL 인젝션을 방지할 수 있다.
아래와 같은 경우가, input 에 이상한 값 넣어버리면 답이 안 나온다.
let query = `SELECT * FROM users WHERE username = '${input}' AND password = '${password}'`;
- ? 사용으로 공격 방지
: ?를 사용하면 값이 자동으로 이스케이프(Escaping) 처리되어 안전하게 쿼리에 포함된다.
사용 예시)
let query = `SELECT * FROM users WHERE username = ? AND password = ?`;
2) 코드 가독성 및 유지보수성 향상
- 값이 많을 경우, 값을 동적으로 추가하는 방식이 가독성을 높이고 유지보수를 쉽게 만든다.
- 코드에서 ?와 values 배열을 사용하면 데이터와 쿼리를 분리하여 더 간결하고 안전한 코드를 작성할 수 있다.
3. 예제 코드에서의 쓰임
- 이 값을 사용하는 예시 코드 일부를 가져와 보았다.
const placeholders = productInfo.map(product => {
values.push(shopName, product.productName, product.productNo, product.productPrice, product.productType, product.maxOrderCount, product.minOrderCount,
product.orderUnit, product.stock, product.isOutOfStock, changeType, product.specification, product.imagePath, JSON.stringify(product.discountInfo),
nowTime, nowTime, useYn, JSON.stringify(product.changedFields));
return '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
}).join(',');
한 상품 데이터에 대한 자리 표시자 생성
- (?, ?, ?, ..., ?)는 SQL에서 **하나의 행(row)**에 대한 자리 표시자이다.
ex) INSERT INTO tb_products (...) VALUES (?, ?, ?, ..., ?)와 같이 하나의 상품 정보를 삽입하는 자리 표시자이다.
여러 상품 데이터의 자리 표시자 생성
- productInfo.map()은 productInfo 배열을 순회하면서 각 상품에 대해 (?, ?, ?, ..., ?)를 생성한다.
- 최종적으로 다수의 상품을 처리하기 위해 쉼표(,)로 연결한다.
예제
const productInfo = [
{ productName: 'Product A', productNo: '123', productPrice: 100, ... },
{ productName: 'Product B', productNo: '124', productPrice: 200, ... }
];
위의 데이터를 처리하면 다음과 같이 자리 표시자가 생성이 된다.
(?, ?, ?, ..., ?), (?, ?, ?, ..., ?)
- 첫 번째 (?, ?, ?, ..., ?)는 첫 번째 상품에 대한 자리 표시자.
- 두 번째 (?, ?, ?, ..., ?)는 두 번째 상품에 대한 자리 표시자.
이와 동시에, values 배열에는 실제 값이 추가된다.
[
'ShopName', 'Product A', '123', 100, ..., // 첫 번째 상품 데이터
'ShopName', 'Product B', '124', 200, ... // 두 번째 상품 데이터
]
4. 최종 SQL 결과
- '?' 는 values 배열의 값으로 대체된다.
INSERT INTO tb_products (shopName, productName, ..., changedFields)
VALUES (?, ?, ?, ..., ?), (?, ?, ?, ..., ?);