지금까지 프로시저를 CREATE OR REPLACE PROCEDURE를 통해 하나씩 독립된 객체로 만들어왔습니다. 하지만 실무에서는 서로 관련 있는 여러 프로시저, 함수, 변수들이 생겨나기 마련입니다. 예를 들어, ‘인사 관리’와 관련된 프로시저(신규 사원 등록, 급여 인상, 퇴사 처리)들이 그렇습니다.
**패키지(Package)**는 이렇게 연관 있는 PL/SQL 객체들을 하나의 논리적인 단위로 묶어 관리하는 객체입니다. 이는 마치 관련된 파일들을 하나의 폴더에 정리하는 것과 같습니다.
## 패키지의 구조: 명세(Specification)와 본문(Body)
패키지는 항상 두 부분으로 나뉩니다.
1. 패키지 명세 (Package Specification)
- 역할: 패키지의 ‘목차’ 또는 ‘설계도’ 역할을 합니다. 외부에서 호출하여 사용할 수 있는 공개(Public) 프로시저, 함수, 변수, 타입 등을 선언합니다.
- 특징: 무엇을 할 수 있는지만 보여주고, 실제 구현 코드는 포함하지 않습니다.
-- 인사 관리 패키지의 명세부 CREATE OR REPLACE PACKAGE PKG_EMP_MANAGEMENT AS -- 공개 프로시저 선언 (외부에서 호출 가능) PROCEDURE HIRE_EMPLOYEE (p_ename IN VARCHAR2, p_sal IN NUMBER); -- 공개 함수 선언 FUNCTION GET_ANNUAL_SALARY (p_empno IN NUMBER) RETURN NUMBER; END PKG_EMP_MANAGEMENT; /
2. 패키지 본문 (Package Body)
- 역할: 명세부에 선언된 프로시저와 함수의 실제 구현 코드가 들어가는 부분입니다.
- 특징: 명세부에는 선언되지 않았지만, 본문 내부에서만 사용하는 비공개(Private) 프로시저나 함수를 추가로 정의할 수 있습니다.
-- 인사 관리 패키지의 본문부
CREATE OR REPLACE PACKAGE BODY PKG_EMP_MANAGEMENT AS
-- 비공개 프로시저 (패키지 내부에서만 호출 가능)
PROCEDURE LOG_HISTORY (p_empno IN NUMBER, p_message IN VARCHAR2) IS
BEGIN
INSERT INTO EMP_HISTORY (EMPNO, MSG, LOG_DATE) VALUES (p_empno, p_message, SYSDATE);
END LOG_HISTORY;
-- 명세부에 선언된 공개 프로시저의 실제 구현
PROCEDURE HIRE_EMPLOYEE (p_ename IN VARCHAR2, p_sal IN NUMBER) IS
v_new_empno NUMBER;
BEGIN
-- 신규 사원 번호 채번 로직...
-- EMP 테이블에 INSERT...
-- 내부의 비공개 프로시저 호출
LOG_HISTORY(v_new_empno, '신규 입사');
COMMIT;
END HIRE_EMPLOYEE;
-- 명세부에 선언된 공개 함수의 실제 구현
FUNCTION GET_ANNUAL_SALARY (p_empno IN NUMBER) RETURN NUMBER IS
v_sal NUMBER;
BEGIN
SELECT SAL * 12 INTO v_sal FROM EMP WHERE EMPNO = p_empno;
RETURN v_sal;
END GET_ANNUAL_SALARY;
END PKG_EMP_MANAGEMENT;
/
## 패키지를 사용해야 하는 이유 (핵심 장점)
1. 코드의 구조화 및 재사용성 향상
관련된 모든 로직이 하나의 패키지 안에 모여 있으므로 코드 관리가 매우 용이합니다. ‘인사 관리’에 대한 로직을 찾고 싶다면 PKG_EMP_MANAGEMENT 패키지만 살펴보면 됩니다.
2. 정보 은닉 (Information Hiding) 및 보안
패키지 명세부에 공개할 것과 본문에 숨길 것을 명확히 구분할 수 있습니다. LOG_HISTORY 프로시저처럼 내부적으로만 사용되는 복잡한 로직은 외부에 노출하지 않고, 개발자에게는 HIRE_EMPLOYEE라는 단순한 인터페이스만 제공하여 실수를 줄이고 보안을 강화할 수 있습니다.
3. 성능 향상
패키지 내의 객체를 처음 호출할 때, Oracle은 패키지 전체를 메모리에 로드합니다. 이후 해당 패키지의 다른 프로시저나 함수를 호출할 때는 디스크 I/O 없이 메모리에서 바로 실행되므로, 독립된 프로시저를 각각 호출하는 것보다 성능상 이점이 있습니다.
4. 전역 변수 및 상태 유지
패키지 명세부에 선언된 변수는 해당 세션이 유지되는 동안 값을 계속 유지하는 **’전역 변수’**처럼 사용할 수 있습니다. 이를 통해 여러 프로시저 호출 간에 데이터를 공유하고 상태를 관리할 수 있습니다.
## 패키지 객체 호출 방법
패키지 내의 프로시저나 함수를 호출할 때는 패키지명.객체명 형식으로 호출합니다.
-- PKG_EMP_MANAGEMENT 패키지의 HIRE_EMPLOYEE 프로시저 호출
EXEC PKG_EMP_MANAGEMENT.HIRE_EMPLOYEE('GILDONG', 3500);
-- PKG_EMP_MANAGEMENT 패키지의 GET_ANNUAL_SALARY 함수 호출
DECLARE
v_annual_sal NUMBER;
BEGIN
v_annual_sal := PKG_EMP_MANAGEMENT.GET_ANNUAL_SALARY(7788);
DBMS_OUTPUT.PUT_LINE('연봉: ' || v_annual_sal);
END;
/
결론적으로, 단일 프로시저로 시작하더라도, 프로그램의 규모가 커지고 관련 기능들이 늘어난다면 반드시 패키지로 전환하는 것을 고려해야 합니다. 패키지는 PL/SQL을 이용한 애플리케이션 개발의 기본이자, 체계적이고 안정적인 시스템을 만드는 핵심 요소입니다.