[Groupware] Database : Oacle DB 세팅

2025. 6. 19. 10:06·Project/Database

📝 개요

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
'Project/Database' 카테고리의 다른 글
  • [DataBase] Oracle + MyBatis SQL
arraysort
arraysort
arraysort 님의 블로그 입니다.
  • arraysort
    arraysort 님의 블로그
    arraysort
  • 전체
    오늘
    어제
    • 분류 전체보기 (14)
      • Study (5)
        • Java (3)
        • DataBase (1)
        • Spring-Boot (1)
        • React (0)
        • WEB (0)
      • Project (9)
        • Backend (5)
        • Frontend (2)
        • Database (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    SQL Mapper
    Database
    VO
    Groupware
    spring boot
    SQL
    utilityclass
    react
    TypeScript
    oracle
    backend
    lombok
    CDB
    API
    java
    DTO
    Spring Security
    objects.eqauls()
    mabatis
    FilterChain
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
arraysort
[Groupware] Database : Oacle DB 세팅
상단으로

티스토리툴바