📝 개요
Oracle Database(오라클 DB)는 세계적으로 많이 사용되는 상용 관계형 데이터 베이스 시스템 중 하나이다. 강력한 안정성, 보안, 대규모 데이터 처리에 최적화 된 아키텍처 덕분에 금융, 공공, 대기업 등 다양한 실무 현장에서 표준처럼 사용한다.
Oracle Database 를 선택한 이유는 회사 및 고객 사이트에서 Oracle DB 를 사용하고 있고 그룹웨어 프로젝트 또한 사내 그룹웨어를 모방한 프로젝트이기 때문에 동일한 환경을 구축하기 위해 사용했다.
개인 프로젝트에서는 오픈소스 DB인 MySQL 과 MariaDB를 사용하면서 MyBaits 와의 연동을 통해서 구축했던 경험이 있지만, 오라클 특유의 구조와 쿼리 최적화, PDB 등 최신 기능을 학습하기 위해 Oracle DB 를 선택했다.
다음은 프로젝트를 초기화 하면서 진해앴던 Oracle DB 세팅에 대해서 설명한다.
🚀 설치
1️⃣ Docker
Docker 는 컨테이너라는 가상화 기술을 사용해서 애플리케이션(혹은 데이터베이스 등)을 서버, 클라우드 어디서나 똑같은 환경으로 실행할 수 있게 도와주는 도구이다. 회사 PC 와 개인 노트북에 동일한 환경을 구축하고 Git 연동을 통해 지속적인 개발을 하기 위해서 Docker 를 통한 DB 설치를 도입하였다.
[ Docker 설치 명령어 (Mac 기준, Windows 는 Docker 공식 페이지를 통해서 다운로드 진행) ]
# brew 설치 (설치 안되어 있다면)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Docker 설치 (GUI 포함 : Docker Desktop)
brew install --cask docker
# Docker 버전 확인
docker --version
Mac 환경에서는 HomeBrew 를 통해서 Docker 를 설치한다. 만약에 설치가 되어 있지 않으면 제일 위의 명령어를 터미널에서 실행한다. —cask 옵션은 Docker Desktop 을 활용하기 위해 GUI 까지 설치하는 옵션이다.
brew 를 통해서 Docker 를 설치하고 버전을 확인한다. 버전을 확인했을 때 # Docker version 27.3.1, build ce1223035a 이런 식으로 출력되면 정상적으로 설치가 완료된 것이다.
[ Docker 삭제 및 재설치 ]
# 실행중인 모든 컨테이너 중지
docker stop $(docker ps -q)
# Docker Desktop 종료 (어플리케이션에서 직접 종료 가능)
osascript -e 'quit app "Docker"'
# HomeBrew 를 통한 삭제 (colima : 로컬 Docker 데몬 대체 도구)
brew uninstall --cask docker
brew uninstall colima
# 패캐지가 --cask 로 설치되어 있지 않은 경우 삭제
brew uninstall docker
# 의존성 패키지 삭제 (캐시 및 디스크 확보)
brew autoremove
brew cleanup
# docker 패키지 설치 위치 확인
brew list | grep docker
# docker 완전 삭제 시 해당 되는 파일 삭제
rm -rf ~/.docker
rm -rf ~/Library/Application\ Support/Docker
rm -rf ~/Library/Containers/com.docker.*
rm -rf /usr/local/bin/docker*
rm -rf /usr/local/bin/com.docker.*
rm -rf ~/.colima
# ls 로 파일 존재 여부 확인
ls -ld ~/.docker
ls -ld ~/Library/Application\ Support/Docker
ls -ld ~/Library/Containers/com.docker.*
ls -l /usr/local/bin/docker*
ls -l /usr/local/bin/com.docker.*
ls -ld ~/.colima
# 재설치
brew install --cask docker
[ Docker 실행 / 중지 ]
# Docker Desktop(앱 전체) 실행 (Mac)
open -a Docker
# 특정 컨테이너 (예 : oracle 컨테이너) 시작
docker start oracle-db
# 모든 중지된 컨테이너 한 번에 시작
docker start $(docker ps -a -q)
##############################################################
# 현재 도커 실행중인지 확인
docker ps
# 현재 실행중인 컨테이너 ID 확인
docker ps -a
# 현재 도커 내에 oracle 실행중인지 확인
docker ps -a | grep oracle
##############################################################
# Docker Desktop(앱 전체) 중지 (Mac)
osascript -e 'quit app "Docker"'
# 특정 컨테이너 (예 : oracle 컨테이너) 중지
docker stop oracle-db
# 모든 실행 중인 컨테이너 한 번에 중지
docker stop $(docker ps -q)
Mac 환경에서 Docker Desktop 이 설치되면 finder 를 통해서 직접 실행시켜도 되지만, 터미널을 통해서 위와 같이 실행할 수 있다. 또한 Docker Desktop UI 를보면서 특정 컨테이너에 대한 시작 중지를 직접 할 수 있다.
2️⃣ Oracle DB
[ Docker 에서 Oracle DB 설치 및 접속 ]
# Docker 실행 상태에서 설치 (Oracle DB 공식 무료 버전 이미지 다운로드)
docker pull gvenzl/oracle-free
# docker 에서 oracle DB 컨테이너 실행
docker run -d \
--name oracle-db \
-e ORACLE_PASSWORD=oracle \
-p 1521:1521 \
-p 5500:5500 \
gvenzl/oracle-free
# DB 설치 및 실행 확인
docker ps
# SYSTEM 계정으로 접속 (PDB: FREEPDB1, 기본 계정)
docker exec -it oracle-db sqlplus system/oracle@//localhost:1521/FREEPDB1
Docker 설치가 완료되면 Docker 가 실행 된 상태에서 Oracle DB 설치 및 접속을 진행한다. Oracle 에서 공식적으로 지원하는 무료 버전 이미지를 다운로드하고 SYSTEM 계정으로 접속하여 sqlplus 로 접속이 되는지 확인한다.
[ Oracle DB 설정 ]
# SYSDBA 권한으로 접속 (컨테이너 안에서)
docker exec -it oracle-db sqlplus sys/oracle@//localhost:1521/FREE as sysdba
# 새로운 PDB 생성 (프로젝트 전용)
CREATE PLUGGABLE DATABASE ${DATABASE_NAME}
ADMIN USER admin IDENTIFIED BY admin
ROLES = (DBA)
FILE_NAME_CONVERT = ('/opt/oracle/oradata/FREEPDB1/', '/opt/oracle/oradata/${DATABASE_NAME}/');
# PDB 상태 확인 : MOUNTED --> OPEN 으로 변경 필요
SHOW PDBS;
# 명령어 실행 시 세션이 PDB에 붙어 있다면 세션 컨테이너를 최상위로 전환
ALTER SESSION SET CONTAINER = CDB$ROOT;
# PDB 상태가 new 라면 해당 명령어로 실행
ALTER PLUGGABLE DATABASE ${DATABASE_NAME} CLOSE IMMEDIATE;
ALTER PLUGGABLE DATABASE ${DATABASE_NAME} OPEN RESTRICTED;
EXEC DBMS_PDB.SYNC_PDB;
# 생성 후 PDB를 OPEN 상태로 변경, PDB OPEN 으로 상태 저장
ALTER PLUGGABLE DATABASE ${DATABASE_NAME} OPEN;
ALTER PLUGGABLE DATABASE ${DATABASE_NAME} SAVE STATE;
프로젝트를 위한 PDB 를 새로 생성한다. ADMIN 권한의 유저를 “admin” 이라는 이름으로 “admin” 이라는 비밀번호로 설정한다. admin 계정은 PDB 내부에서 DBA 권한이 있는 관리자로 동작하게 된다. 이 권한 덕분에 테이블 생성, 계정 관리, 권한 부여 등 모든 작업이 가능하다. FILE_NAME_CONVERT 를 통해서 PDB 의 실제 데이터 파일 경로를 지정한다. 기본 샘플인 FREEPDB1 을 참고해서 신규 PDB 의 데이터 파일 디렉토리를 분리한다.
ALTER SESSION SET CONTAINER = CDB$ROOT; 를 실행하는 이유는 PDB 를 생성하면서 세션이 PDB 세션으로 변경될 수 있다. 보통 SYSDBA 접속 시 CDB$ROOT 로 설정되 어 있지만, 다른 컨테이너에 붙어 있을 경우 PDB 를 설정하는 CDB 레벨의 명령어를 실행할 때 필요하다. (PDB 상태 변경 및 저장 등)
Oracle DB 버전에 따라서 PDB 생성 직후 NEW 상태가 유지되어 바로 OPEN 이 안되고, 위 명령어로 CLOSE/OPEN RESTRICTED/SYNC_PDB 순서로 한 번 동기화해야 정상적으로 OPEN 되는 경우가 있다.
🚀 DDL (테이블 생성)
1️⃣ 테이블 스페이스 설정
[ 테이블 생성 시 발생하는 오류 : 테이블 스페이스 문제 ]
# 테이블 스페이스 문제
oracle.jdbc.OracleDatabaseException: ORA-01950: 사용자 ADMIN에게는 SYSTEM 테이블스페이스에 대한 할당량이 부족합니다.
# ADMIN 계정에 SYSTEM 또는 별도 테이블 스페이스 사용 권한(할당량) 부여
ALTER USER ADMIN QUOTA UNLIMITED ON SYSTEM;
ALTER USER ADMIN QUOTA UNLIMITED ON USERS;
PDB 를 만들고 ADMIN 계정으로 접속해서 테이블을 만들려고 할 때 발생한다. Oracle DB 는 사용자가 테이블을 만들면 테이블 스페이스라는 논리적 공간 (실제로는 물리 디스크) 에 데이터를 저쟁해야 한다. 기본저긍로 새로 만든 AMDIN 계정에는 SYSTEM 테이블 스페이스에 할당량이 0으로 설정돼 있어 에러가 발생한다.
2️⃣ 프로젝트 테이블, 인덱스, 시퀀스 생성
[ Groupware 프로젝트 테이블, 인덱스, 시퀀스 생성 DDL ]
/**
2025. 04. 09 기준 DDL
@Author : 안영준
*/
-- USERS 테이블 생성
CREATE TABLE USERS (
USER_ID VARCHAR2(50) PRIMARY KEY,
USER_PASSWORD VARCHAR2(255) NOT NULL,
USER_NAME VARCHAR2(50),
USER_BIRTH DATE,
USER_NUMBER VARCHAR2(20),
USER_DEPARTMENT VARCHAR2(100),
USER_RESPONSIBILITY VARCHAR2(20),
USER_POSITION VARCHAR2(20),
USER_HIRE_DATE DATE,
USER_PROMOTION_DATE DATE,
USER_AUTH VARCHAR2(10),
USER_LOGIN_TRY_COUNT NUMBER DEFAULT 0,
IS_DELETE CHAR(1) DEFAULT 'N',
CREATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
UPDATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(50),
UPDATED_BY VARCHAR2(50),
IS_LOCKED CHAR(1) DEFAULT 'N',
USER_EMAIL VARCHAR2(100),
USER_RESIGN_DATE DATE
);
-- NOTICE 테이블 생성
CREATE TABLE NOTICE (
NOTICE_ID NUMBER(19) PRIMARY KEY,
USER_ID VARCHAR2(50) NOT NULL,
NOTICE_TITLE VARCHAR2(200) NOT NULL,
NOTICE_CONTENT CLOB NOT NULL,
NOTICE_VIEWS NUMBER(19) DEFAULT 0 NOT NULL,
IS_DELETE CHAR(1) DEFAULT 'N',
IS_PINNED CHAR(1) DEFAULT 'N',
CREATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
UPDATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(30) NOT NULL,
UPDATED_BY VARCHAR2(30) NOT NULL,
CHECK (IS_DELETE IN ('Y', 'N')),
CHECK (IS_PINNED IN ('Y', 'N'))
);
-- NOTICE 시퀀스
CREATE SEQUENCE NOTICE_SEQ
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- REPORT 테이블 생성
CREATE TABLE REPORT (
REPORT_ID NUMBER(19) PRIMARY KEY,
USER_ID VARCHAR2(50) NOT NULL,
REPORT_YEAR NUMBER(4) NOT NULL,
REPORT_WEEK NUMBER(2) NOT NULL,
REPORT_PROJECT CLOB,
REPORT_WORK CLOB NOT NULL,
IS_DELETE CHAR(1) DEFAULT 'N',
CREATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
UPDATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(30),
UPDATED_BY VARCHAR2(30)
);
-- REPORT 시퀀스
CREATE SEQUENCE REPORT_SEQ
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- 2025. 04. 06 : 보고서 리스트 조회 시 직위 별 정렬을 위해서 필드 추기
ALTER TABLE USERS
ADD USER_POSITION_RANK NUMBER(2);
-- 2025. 04. 09 : VACATION 테이블 생성
-- 휴가 테이블
CREATE TABLE VACATION (
VACATION_ID NUMBER(19) PRIMARY KEY,
USER_ID VARCHAR2(50) NOT NULL,
VACATION_TITLE VARCHAR2(50) NOT NULL,
VACATION_CONTENT CLOB NOT NULL,
VACATION_TYPE VARCHAR2(20) NOT NULL, -- ENUM → VARCHAR2 처리
VACATION_IS_OFFICIAL CHAR(1) NOT NULL,
VACATION_START_DATE DATE NOT NULL,
VACATION_END_DATE DATE NOT NULL,
FIRST_APPROVER_ID VARCHAR2(50) NOT NULL,
SECOND_APPROVER_ID VARCHAR2(50) NOT NULL,
VACATION_STATUS VARCHAR2(30) NOT NULL, -- ENUM → VARCHAR2 처리
VACATION_CANCEL_REASON CLOB,
VACATION_REJECT_REASON CLOB,
IS_DELETED CHAR(1) DEFAULT 'N' NOT NULL,
CREATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
UPDATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(30) NOT NULL,
UPDATED_BY VARCHAR2(30) NOT NULL,
CHECK (VACATION_IS_OFFICIAL IN ('Y', 'N')),
CHECK (IS_DELETED IN ('Y', 'N')),
CHECK (VACATION_STATUS IN ('PENDING', 'APPROVED_FIRST', 'APPROVED_SECOND',
'REQUESTED_CANCEL', 'CANCELED', 'REJECTED')),
CHECK (VACATION_TYPE IN ('FULL', 'AM', 'PM', 'AM_HALF', 'PM_HALF', 'AM_QUARTER', 'PM_QUARTER'))
);
-- VACATION 시퀀스 생성
CREATE SEQUENCE VACATION_SEQ
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- 2025. 04. 09 : VACATION_BALANCE 테이블 생성
CREATE TABLE VACATION_BALANCE (
VACATION_BALANCE_ID NUMBER(19) PRIMARY KEY,
USER_ID VARCHAR2(50) NOT NULL,
YEAR NUMBER(4) NOT NULL,
VACATION_GRANT_DAYS NUMBER(4,1) NOT NULL,
VACATION_USED_DAYS NUMBER(4,1) NOT NULL,
VACATION_REMAINING_DAYS NUMBER(4,1) NOT NULL,
UPDATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- 시퀀스 생성
CREATE SEQUENCE VACATION_BALANCE_SEQ
START WITH 1
INCREMENT BY 1
NOCACHE
NOCYCLE;
-- VACATION 인덱스
CREATE INDEX IDX_VACATION_USER_ID ON VACATION(USER_ID);
CREATE INDEX IDX_VACATION_STATUS ON VACATION(VACATION_STATUS);
CREATE INDEX IDX_VACATION_FIRST_APPROVER ON VACATION(FIRST_APPROVER_ID);
CREATE INDEX IDX_VACATION_SECOND_APPROVER ON VACATION(SECOND_APPROVER_ID);
CREATE INDEX IDX_VACATION_START_DATE ON VACATION(VACATION_START_DATE);
CREATE INDEX IDX_VACATION_END_DATE ON VACATION(VACATION_END_DATE);
-- VACATION_BALANCE 인덱스
CREATE INDEX IDX_BALANCE_USER_ID ON VACATION_BALANCE(USER_ID);
CREATE INDEX IDX_BALANCE_YEAR ON VACATION_BALANCE(YEAR);
-- IMAGE 테이블 생성 (2025. 04. 30)
CREATE TABLE IMAGE (
IMAGE_ID NUMBER(19) PRIMARY KEY,
IMAGE_ORIGINAL_NAME VARCHAR2(100) NOT NULL,
IMAGE_SAVED_NAME VARCHAR2(100) NOT NULL,
IMAGE_SIZE NUMBER(19) NOT NULL,
IMAGE_PATH VARCHAR2(200) NOT NULL,
IS_DELETED CHAR(1) DEFAULT 'N' CHECK (IS_DELETED IN ('Y', 'N')),
CREATED_AT TIMESTAMP(0) DEFAULT CURRENT_TIMESTAMP,
CREATED_BY VARCHAR2(50),
UPDATED_BY VARCHAR2(50)
);
-- IMAGE 시퀀스 생성
CREATE SEQUENCE IMAGE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
-- USER_IMAGE 테이블 생성 (2025. 04. 30)
CREATE TABLE USER_IMAGE (
USER_IMAGE_ID NUMBER(19) PRIMARY KEY,
USER_ID VARCHAR2(50) NOT NULL,
IMAGE_ID NUMBER(19) NOT NULL
);
-- USER_IMAGE 시퀀스 생성
CREATE SEQUENCE USER_IMAGE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
-- NOTICE_IMAGE 테이블 생성 (2025. 04. 30)
CREATE TABLE NOTICE_IMAGE (
NOTICE_IMAGE_ID NUMBER(19) PRIMARY KEY,
NOTICE_ID NUMBER(19) NOT NULL,
IMAGE_ID NUMBER(19) NOT NULL
);
-- NOTICE_IMAGE 시퀀스 생성
CREATE SEQUENCE NOTICE_IMAGE_SEQ START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE;
'Project > Database' 카테고리의 다른 글
| [DataBase] Oracle + MyBatis SQL (1) | 2025.06.25 |
|---|
