
이번 시간엔 주문 API 전부 구현해볼 예정입니다.
데이터 조작어(DML): 테이블에서 특정 행(Row)을 선택하여 삭제하는 명령어입니다.
조건부 삭제: WHERE 절을 사용하여 원하는 데이터만 골라 삭제할 수 있다는 것이 가장 큰 특징입니다.
로그 기록 및 속도: 삭제하는 행마다 로그를 남기기 때문에 처리 속도가 상대적으로 느리지만, ROLLBACK을 통해 삭제 전으로 복구가 가능합니다.
ID 값 유지: 데이터를 지워도 AUTO_INCREMENT로 설정된 기본키 값은 초기화되지 않고 유지됩니다. (예: 10번까지 쓰고 지우면 다음 데이터는 11번부터 시작)
데이터 정의어(DDL): 테이블의 구조만 남기고 데이터 전체를 순식간에 비우는 명령어입니다.
전체 삭제 전용: WHERE 절을 사용할 수 없으며, 무조건 테이블의 모든 행을 삭제합니다.
로그 최소화 및 속도: 개별 행을 삭제하는 로그를 남기지 않고 테이블 공간 자체를 해제하기 때문에 대용량 데이터를 비울 때 속도가 매우 빠릅니다.
ID 값 초기화: 테이블을 처음 생성했을 때와 같은 상태로 되돌리기 때문에 AUTO_INCREMENT 값이 1번부터 다시 시작됩니다.
복구 불가: 실행 즉시 커밋되어 ROLLBACK으로 데이터를 되살릴 수 없으므로 주의해서 사용해야 합니다.
외래키 제약 조건 일시 해제
SET FOREIGN_KEY_CHECKS = 0; -- 외래키 제약 해제
DELETE FROM orders; -- 또는 TRUNCATE TABLE orders;
SET FOREIGN_KEY_CHECKS = 1; -- 외래키 제약 복구
지난 시간에 배운 비동기처리를 활용하여 코드를 수정하고 주문 완료 후 장바구니에 상품을 삭제해볼 예정입니다.
👉🏻 비동기처리 확인하기
export const order = async (req, res) => {
const { items, delivery, totalQuantity, totalPrice, userId, firstBookTitle } =
req.body;
const promiseConn = conn.promise();
try {
let sql = `INSERT INTO delivery (address, receiver, contact) VALUES (?, ?, ?)`;
let values = [delivery.address, delivery.receiver, delivery.contact];
let [results] = await promiseConn.execute(sql, values);
const delivery_id = results.insertId;
sql = `INSERT INTO orders (book_title, total_quantity, total_price, user_id, delivery_id)
VALUES (?, ?, ?, ?, ?)`;
values = [firstBookTitle, totalQuantity, totalPrice, userId, delivery_id];
[results] = await promiseConn.execute(sql, values);
const order_id = results.insertId;
sql = `INSERT INTO orderedBook (order_id, book_id, quantity) VALUES ?`;
const itemValues = items.map((item) => [
order_id,
item.book_id,
item.quantity,
]);
await promiseConn.query(sql, [itemValues]);
const cartIds = items.map((item) => item.cart_id);
await deleteCartItems(promiseConn, cartIds);
return res
.status(StatusCodes.CREATED)
.json({ message: "주문 완료 및 장바구니가 비워졌습니다.", order_id });
} catch (err) {
console.error("주문 처리 중 에러 발생:", err);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
}
};
export const order = async (req, res): async 함수로 선언 → 비동기 작업 처리 가능const promiseConn = conn.promise(): Promise 기반 데이터베이스 연결 객체 생성req.body에서 주문 정보(상품, 배송 정보, 수량, 가격 등)를 받습니다await promiseConn.execute(sql, values)- 배송 정보 저장 완료될 때까지 대기 → delivery_id 획득wait promiseConn.execute(sql, values) - 주문 정보 저장 완료될 때까지 대기 → order_id 획득await promiseConn.query(sql, [itemValues]) - 상품 일괄 저장 완료될 때까지 대기await deleteCartItems(promiseConn, cartIds) - 장바구니 삭제 완료될 때까지 대기export const deleteCartItems = async (promiseConn, cartIds) => {
const sql = `DELETE FROM cart WHERE cart_id IN (?)`;
const [result] = await promiseConn.query(sql, [cartIds]);
return result;
};
export const deleteCartItems = async (promiseConn, cartIds): async 함수로 선언const sql = DELETE FROM cart WHERE cart_id IN (?): 여러 개의 cart_id를 한 번에 삭제하는 SQL 쿼리const [result] = await promiseConn.query(sql, [cartIds]): await로 삭제 작업 완료될 때까지 대기return result: 삭제 결과 반환 (몇 개의 행이 삭제되었는지 확인 가능)

orders 테이블과 delivery 테이블을 LEFT JOIN으로 연결하여 모든 주문과 배송 정보를 조회합니다. 200 OK 상태 코드로 결과를 반환합니다.
export const getOrders = async (req, res) => {
const promiseConn = conn.promise();
try {
const sql = `
SELECT
orders.order_id,
orders.book_title,
orders.total_quantity,
orders.total_price,
orders.created_at,
delivery.address,
delivery.receiver,
delivery.contact
FROM orders
LEFT JOIN delivery ON orders.delivery_id = delivery.delivery_id
`;
const [results] = await promiseConn.execute(sql);
return res.status(StatusCodes.OK).json(results);
} catch (err) {
console.error("주문 목록 조회 중 에러:", err);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
}
};
export const getOrders = async (req, res): async 함수로 선언const promiseConn = conn.promise(): Promise 기반 데이터베이스 연결 객체 생성const [results] = await promiseConn.execute(sql): await로 SQL 쿼리 완료될 때까지 대기LEFT JOIN: orders 테이블의 모든 행을 포함하고 delivery 테이블의 일치하는 배송 정보를 함께 조회
특정 주문(order_id)의 orderedBook 테이블과 books 테이블을 LEFT JOIN으로 연결하여 주문한 책의 상세 정보(제목, 저자, 가격, 수량)를 조회합니다. 결과가 없으면 404 Not Found를 반환합니다.
export const getOrderDetail = async (req, res) => {
const { id } = req.params;
const promiseConn = conn.promise();
try {
const sql = `
SELECT
ob.book_id,
b.title AS book_title,
b.author,
b.price,
ob.quantity
FROM orderedBook AS ob
LEFT JOIN books AS b ON ob.book_id = b.book_id
WHERE ob.order_id = ?
`;
const [results] = await promiseConn.execute(sql, [id]);
if (results.length === 0) {
return res.status(StatusCodes.NOT_FOUND).json({
message: "해당 주문의 상세 내역을 찾을 수 없습니다.",
});
}
return res.status(StatusCodes.OK).json(results);
} catch (err) {
console.error("주문 상세 조회 중 에러:", err);
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json(err);
}
};
export const getOrderDetail = async (req, res): async 함수로 선언const { id } = req.params: URL 경로 파라미터에서 order_id를 추출 (예: /orders/5 → id = 5)const promiseConn = conn.promise(): Promise 기반 데이터베이스 연결 객체 생성const [results] = await promiseConn.execute(sql, [id]): await로 SQL 쿼리 완료될 때까지 대기LEFT JOIN: orderedBook 테이블과 books 테이블을 연결하여 주문한 책의 상세 정보 조회WHERE ob.order_id = ?: 특정 주문에 해당하는 상품들만 필터링