데이터베이스 작업을 할 때 우리는 종종 예외 상황을 만나게 됩니다. 특히, 대규모 트랜잭션을 처리하거나 중요한 비즈니스 로직을 다룰 때 예외 처리는 안정성을 보장하는 중요한 요소 중 하나입니다. MySQL을 사용할 때 예외 처리를 다루는 방법은 크게 두 가지로 나뉩니다. 하나는 저장 프로시저 내에서 직접 예외를 처리하는 방법 이고, 다른 하나는 프로그램 단(TypeScript)에서 예외를 처리하는 방법 입니다.
이 글에서는 두 방법에 대해 각각 살펴보고, 각 방법이 가지는 장점과 단점에 대해 설명하겠습니다. 또한, 실제로 사용할 수 있는 예제 코드도 함께 제공하여 이해를 돕고자 합니다.
1. MySQL 저장 프로시저에서 예외 처리
저장 프로시저는 데이터베이스 내에서 복잡한 로직을 한 번에 처리할 수 있도록 해주는 도구입니다. 예를 들어, 특정 조건에 따라 데이터를 업데이트하거나 삽입하는 작업을 묶어서 처리할 수 있습니다. 저장 프로시저의 강력한 기능 중 하나는 예외를 직접 처리할 수 있다는 점 입니다.MySQL에서는 DECLARE ... HANDLER
구문을 통해 특정 예외 상황이 발생했을 때 처리할 로직을 정의할 수 있습니다. 이렇게 하면 예외 상황에 맞춰 데이터베이스 레벨에서 즉각적인 처리가 가능하게 됩니다.
저장 프로시저 내에서의 예외 처리 예제
다음은 송금하는 로직에서 잔액이 부족할 경우 발생할 수 있는 예외를 처리하는 예제입니다.
DELIMITER $$
CREATE PROCEDURE transfer_funds(IN sender_id INT, IN receiver_id INT, IN amount DECIMAL(10,2))
BEGIN
DECLARE insufficient_funds CONDITION FOR SQLSTATE '45000'; -- 사용자 정의 예외
DECLARE CONTINUE HANDLER FOR insufficient_funds
BEGIN
-- 예외 발생 시 로그 남기기
INSERT INTO error_log (error_message) VALUES ('Insufficient funds');
END;
-- 가상의 조건: 송금자의 잔액이 부족할 경우 예외 발생
IF (SELECT balance FROM accounts WHERE id = sender_id) < amount THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient funds';
ELSE
-- 잔액 이체 로직
UPDATE accounts SET balance = balance - amount WHERE id = sender_id;
UPDATE accounts SET balance = balance + amount WHERE id = receiver_id;
END IF;
END$$
DELIMITER ;
이 예제에서 DECLARE ... HANDLER
는 잔액이 부족할 때 발생하는 SQLSTATE '45000'
상태를 처리하도록 설정되었습니다. 예외가 발생하면 단순히 오류를 로그에 남기고 트랜잭션을 취소하는 대신, 우리가 원하는 특정 로직을 수행할 수 있습니다.
저장 프로시저에서 예외 처리를 하는 이유
- 즉각적인 예외 처리 : 예외가 발생했을 때 데이터베이스 레벨에서 바로 처리할 수 있습니다. 이는 서버 또는 클라이언트 측에서 추가적으로 예외를 처리하지 않아도 된다는 점에서 효율적입니다.
- 일관성 유지 : 저장 프로시저 내에서 모든 예외 처리 로직을 통일하면, 여러 클라이언트가 동일한 로직을 일관되게 사용할 수 있습니다. 즉, 프로시저를 호출하는 방식만 달라질 뿐, 데이터베이스 레벨에서 처리하는 로직은 동일하게 유지됩니다.
- 성능 최적화 : 프로그램 단에서 처리하는 것보다 데이터베이스 내에서 직접 처리하는 것이 더 빠를 수 있습니다. 특히 트랜잭션 처리에서 즉시 예외를 검출하고 대응할 수 있다는 점에서 성능적인 이점이 있습니다.
그러나 저장 프로시저 내에서의 예외 처리는 복잡한 로직을 처리하기에는 제한적일 수 있습니다. 저장 프로시저는 고정된 로직을 따르기 때문에, 프로그램 단에서 더 복잡한 로직을 구현하는 것에 비해 유연성이 떨어질 수 있습니다. 그래서 경우에 따라서는 프로그램 단에서 예외 처리를 해야 할 때도 있습니다.
2. 프로그램 단에서의 예외 처리
두 번째 방법은 프로그램 단에서 직접 예외를 처리하는 방법 입니다. 보통 Node.js나 TypeScript 같은 환경에서 데이터베이스와 상호작용할 때 이 방법을 사용합니다. 특히 비즈니스 로직이 복잡하거나, 사용자에게 좀 더 세밀한 피드백을 주어야 하는 경우에는 프로그램 단에서 예외를 처리하는 것이 더 적합할 수 있습니다.
프로그램 단에서의 예외 처리는 데이터베이스에서 발생하는 예외 상황을 프로그램이 직접 감지하고, 그에 따라 로직을 처리하는 방식입니다. 즉, SQL 쿼리를 실행하고 그 결과를 바탕으로 프로그램이 예외를 처리하게 됩니다.
프로그램 단에서 예외 처리 예제 (TypeScript + MySQL)
다음은 송금 로직을 TypeScript에서 직접 처리하는 예제입니다. 여기서는 저장 프로시저 대신 인라인 쿼리 를 사용하여 예외를 처리합니다.
import mysql from 'mysql2/promise';
async function transferFunds(senderId: number, receiverId: number, amount: number) {
const connection = await mysql.createConnection({
host: 'localhost',
user: 'root',
database: 'test',
password: 'password',
});
try {
await connection.beginTransaction();
// 송금자의 잔액 확인
const [sender] = await connection.execute('SELECT balance FROM accounts WHERE id = ?', [senderId]);
const senderBalance = sender[0].balance;
if (senderBalance < amount) {
throw new Error('Insufficient funds');
}
// 잔액 업데이트
await connection.execute('UPDATE accounts SET balance = balance - ? WHERE id = ?', [amount, senderId]);
await connection.execute('UPDATE accounts SET balance = balance + ? WHERE id = ?', [amount, receiverId]);
await connection.commit();
console.log('Funds transferred successfully');
} catch (error) {
await connection.rollback();
// 오류 메시지에 따라 예외 처리
if (error.message.includes('Insufficient funds')) {
console.error('Transfer failed: Insufficient funds');
} else {
console.error('Transfer failed:', error.message);
}
} finally {
await connection.end();
}
}
// 예시 실행
transferFunds(1, 2, 100.00);
이 예제에서 transferFunds
함수는 송금자의 잔액을 확인한 뒤 조건에 맞춰 잔액을 업데이트하는 로직을 실행합니다. 만약 송금자의 잔액이 부족하면 예외를 발생시키고, 이를 catch
블록에서 처리합니다. 예외 발생 시에는 트랜잭션을 롤백하고, 에러 메시지를 출력하게 됩니다.
프로그램 단에서의 예외 처리 장점
- 유연성 : 프로그램 단에서 예외를 처리하면 복잡한 비즈니스 로직을 손쉽게 구현할 수 있습니다. 저장 프로시저는 고정된 로직에 의존하지만, 프로그램 단에서는 다양한 예외 상황에 맞춰 맞춤형 처리가 가능합니다.
- 상세한 피드백 제공 : 사용자가 예외 상황에 대해 더 정확하고 세부적인 피드백을 받을 수 있습니다. 프로그램은 예외 발생 시 그에 맞는 사용자 메시지를 보여줄 수 있으며, 이로 인해 사용자 경험이 향상됩니다.
- 트랜잭션 관리 : 프로그램 단에서 트랜잭션을 제어할 수 있어 복잡한 트랜잭션 처리 로직을 보다 쉽게 구현할 수 있습니다.
프로그램 단에서의 예외 처리 단점
- 성능 저하 : 데이터베이스 레벨에서 처리하는 것보다 프로그램에서 예외를 처리하면 성능이 다소 저하될 수 있습니다. 특히 트랜잭션이 많거나 복잡한 로직이 포함될 경우 성능이 문제가 될 수 있습니다.
- 추가적인 코드 작성 필요 : 프로그램에서 예외를 처리하려면 추가적인 로직을 구현해야 하므로 코드가 복잡해질 수 있습니다. 특히 복잡한 트랜잭션 로직을 처리할 때 코드가 길어질 수 있습니다.
결론: 어느 방법이 더 좋은가?
저장 프로시저 내에서 예외 처리를 하는 것과 프로그램 단에서 예외를 처리하는 것 모두 각각의 장점이 있습니다.
- 저장 프로시저에서의 예외 처리 는 데이터베이스 레벨에서 처리하기 때문에 일관성 과 성능 면에서 유리합니다. 특히 데이터베이스 트랜잭션의 일관성을 유지하고, 여러 클라이언트에서 동일한 로직을 사용할 때 적합합니다.
- 반면, 프로그램 단에서의 예외 처리 는 유연성 과 사용자 피드백 측면에서 더 강력합니다. 복잡한 비즈니스 로직을 처리하거나 사용자에게 맞춤형 오류 메시지를 제공할 수 있는 점에서 유리합니다.
따라서 복잡한 트랜잭션 처리와 사용자 경험이 중요한 경우 에는 프로그램 단에서의 예외 처리가 더 적합하고, 데이터베이스 레벨에서 성능과 일관성을 중시하는 경우 에는 저장 프로시저 내에서 예외 처리를 사용하는 것이 좋습니다.
'DataBase' 카테고리의 다른 글
MySQL 프로시저에서 예외 처리 (2) | 2024.12.09 |
---|---|
효율적인 데이터베이스 관리를 위한 MySQL 이벤트 사용법 (1) | 2024.11.07 |
MSSQL의 FORMAT 함수 가이드: 사용법, 대체 방법, 실전 사례 (2) | 2024.11.04 |
[MSSQL] CHARINDEX 함수 가이드: 문자열 위치 찾기와 활용법 (0) | 2024.11.02 |
[MSSQL] SUBSTRING 함수 완벽 가이드 - 문자열 추출과 데이터 마스킹 활용법 총정리 (1) | 2024.11.02 |