본문 바로가기
실험실/db이행

핵심 유즈케이스

by 죄니안죄니 2026. 1. 14.
반응형

다만 “어디까지 자동으로 되고, 어디부터는 설계가 필요한지”를 명확히 구분해야 한다.
아래를 단계별로 차근차근 정리할게.


1️⃣ 결론부터 정리

✔ 할 수 있는 것

  • 화면의 조회 버튼으로
    → Oracle 객체 목록(TABLE / VIEW / SEQUENCE / INDEX / TRIGGER 등) 조회
  • 사용자가 체크한 객체만 선택
  • 파일 다운로드 버튼으로
    → CSV / SQL 등 변환 결과 파일 생성 및 다운로드

✔ 기술적으로 자연스러운 흐름

  • Ora2Pg를 “변환 엔진” (데이터변환, CSV 포맷 생성, 타입매핑구현, 대용량데이터스트리밍 작업)
  • 백엔드를 “오케스트레이터” ( ① 접속정보유효성확인, 변환타입설정, 실행순서결정 등 의사결정, ② JobID발급과 상태관리 Job별 디렉토리 생성같은 작업의 생애주기 관리, ③ Ora2Pg 나 도커컨테이너 혹은 로컬같은 도구를 호출, ④ 흐름을 연결 관리(오라클객체조회->사용자선택수신->ora2pg.conf생성 -> Ora2Pg실행 -> 결과파일정리->다운가능한 상태로 전환, ⑤ 결과전달 (로그 스트리밍, 상태조회API, 결과파일다운로드. 즉 UI와 실행환경사이 브리지) )
  • 프론트를 “선택·제어 UI”

👉 앱의 정석적인 사용 시나리오

 

더보기

🎼 오케스트라 비유

역할 이 앱에서
지휘자 Backend
악보 ora2pg.conf
연주자 Ora2Pg
무대 Docker / Local
관객 React UI

👉 오케스트레이터는:

  • 바이올린 연주법 모름
  • 트럼펫 소리 안 냄
  • 하지만 전체 곡은 완성시킨다

오케스트레이터 설계의 핵심 원칙 (3줄)

  1. 변환 로직은 도구에 위임
  2. 백엔드는 순서와 상태만 관리
  3. 실행 환경은 추상화

코드 레벨에서 보면 이렇게 달라진다

❌ 잘못된 백엔드 설계

def migrate():
    rows = oracle.select(...)
    for r in rows:
        csv.write(convert(r))

👉 백엔드가 “일꾼”이다.

✅ 오케스트레이터 백엔드

def migrate():
    job = create_job()
    config = build_ora2pg_config(job)
    runner.run(config)

👉 백엔드는:

  • 판단
  • 준비
  • 호출
  • 관리만 한다

 

 


2️⃣ 전체 동작 흐름 (한 번에 그림 그리기)

[React 화면]
 ├─ Oracle 접속 정보 입력 (Oracle Host, Port, SID / Service Name, User,Password,Schema)
 ├─ [조회] 버튼 
 │
 v
[Backend API]
 ├─ Oracle 메타데이터 조회 (단순 DB 커넥션만 사용: 접속 테스트, 권한 확인, 객체 목록 조회)
 ├─ 객체 목록 반환 ({tables: [...], views: [...], sequences: [...] ... })
 │
 v
[React 화면]
 ├─ TABLE / VIEW / … 목록 표시
 ├─ 체크박스 선택 
 ├─ 출력 포맷 선택 (CSV / SQL)
 ├─ [변환실행 혹은 파일 다운로드] 버튼
 │
 v
[Backend API]
 ├─ ora2pg.conf 동적 생성
 ├─ Ora2Pg 실행(Docker/Local)
 ├─ 결과 파일 생성
 └─ 파일 다운로드 응답

3️⃣ 조회 버튼으로 Oracle 객체 목록 사전조회

핵심 포인트

👉 이 단계에서는 Ora2Pg를 쓰지 않아도 된다. 쓸 필요가 없다.

왜냐하면:

  • 객체 목록 조회는 변환이 아니기 때문에
  • 메타데이터 조회이기 때문 가볍고, 빠르게 작업
[React 화면]
   |
   | 접속정보 
   | (DB 접속정보를 애플리케이션 실행 시점이 아니라, 실행시점을 입력한 시점에 접속하도록 설계)
   v
[Backend]
   |
   | JDBC / oracledb 드라이버 
   | (① Python oracledb (thin 모드), Instant Client 없이 가능)
   | (② Oracle Instant Client, Docker 이미지 내부에 포함)
   v
[Oracle DB]

백엔드에서 하는 일

Oracle 시스템 뷰 조회:

-- 테이블
SELECT table_name
FROM all_tables
WHERE owner = :schema;

-- 뷰
SELECT view_name
FROM all_views
WHERE owner = :schema;

-- 시퀀스
SELECT sequence_name
FROM all_sequences
WHERE sequence_owner = :schema;

👉 이건

  • Python(cx_Oracle / oracledb)
  • Java
  • 어떤 언어로도 가능

📌 이 단계는 빠르고, 안전하고, 실패 가능성 낮다.

**

더보기

화면에서 접속정보를 받아야 하므로 

❌ 앱 실행 시점에 DB 연결하면 목적 앱에 부합하지 않음

  • 특정 Oracle에 종속
  • 접속 정보가 코드/설정에 남음
  • 사용자별 DB 연결 불가
  • 보안 사고 위험
  • 멀티 테넌트 불가능

👉 툴이 아니라 “서버”가 돼버린다

앱의 성격

  • 어떤 Oracle이든 연결 가능
  • 사용자별 / 프로젝트별 분리
  • Job 단위로 격리
  • 실행 후 즉시 접속 정보 폐기 가능( 입력 → 메모리 보관, Job실행, 즉시파기 )
  • 👉 Docker / subprocess 방식이 이걸 자연스럽게 만족 (저장 별도 안하면, Jab 내부 메모리에서만 쓰면, 프로세스 종료되면, OS가 메모리 해제)
  • conf파일에 장지저장, 로그에 출력, DB에 저장 금지 

***

Job 단위 접속정보 수명: 파일 아닌 메모리변수로만 존재하도록.

더보기

Job 실행 함수의 로컬 메모리 변수로만 존재

프로세스 종료 시 → OS 레벨에서 메모리는 즉시 해제(다른 프로세스 접근 불가, 운영체제가 자동으로 정리)

  • 함수 스코프 종료
  • 프로세스 종료 or 스레드 종료
  • 메모리 해제

❌ 자동 파괴가 깨지는 경우

  1. 전역 변수에 저장
  2. 캐시(redis 등)에 저장
  3. 파일로 기록
  4. 로그에 출력
  5. Job 종료 후 재사용
  6. 예외 발생 시 참조 유지

👉 이러면:

  • 프로세스 살아 있는 동안 계속 남아 있음
  • 심지어 메모리 덤프 시 노출 가능

✔ 반드시 지켜야 할 설계 원칙

① 접속 정보는 Job Context 내부에만

 
def run_job(request):
    oracle_conn = request.oracle
    # 여기서만 사용

❌ 이렇게 하면 안 됨

 
GLOBAL_ORACLE_INFO = request.oracle
 

② Job 종료 시 참조 끊기기

 
oracle_conn = None

이건 필수는 아니지만 안전장치다.


③ 파일 생성 금지 (중요)

  • ora2pg.conf에 비밀번호 들어가면?
    • 실행 후 즉시 삭제
  • 임시 디렉터리 사용
  • Job 종료 시 디렉터리 통째로 제거
/tmp/job-1234/
  └─ ora2pg.conf  ← 실행 후 rm -rf

④ 로그 마스킹

 
ORACLE_PWD=********

로그에 평문 출력 ❌

Job 기반 구조에서 실제 수명 타임라인

 
[요청 수신]
   |
   | 접속정보 파싱
   v
[Job 생성]
   |
   | 메모리 변수에 저장
   v
[Oracle 조회 / Ora2Pg 실행]
   |
   v
[Job 종료]
   |
   | 참조 제거
   | 임시 파일 삭제
   v
[프로세스 종료 or 대기]

👉 이 시점 이후엔 접근 불가능


4️⃣ “파일 다운로드 버튼 → CSV / SQL 생성”은 어떻게 이어지나?

여기서 Ora2Pg가 등장한다.

화면에서 전달되는 정보 예시

{
  "schema": "HR",
  "tables": ["EMP", "DEPT"],
  "views": ["EMP_VIEW"],
  "outputType": "CSV"
}
 

백엔드 처리 흐름

① ora2pg.conf 동적 생성

ORACLE_DSN  dbi:Oracle:host=...
ORACLE_USER ...
ORACLE_PWD  ...

SCHEMA HR
ALLOW EMP,DEPT,EMP_VIEW

TYPE COPY
OUTPUT data.csv

② Ora2Pg 실행

ora2pg -c /tmp/job123/ora2pg.conf

③ 결과 파일 생성

  • /tmp/job123/data.csv
  • /tmp/job123/schema.sql

④ 다운로드 응답

  • 단일 파일
  • 또는 ZIP 압축

5️⃣ CSV 말고 “다른 파일”도 가능하나?

가능하다. 범위는 아래 정도가 현실적이다.

✔ 현실적으로 추천되는 출력

포맷 설명
CSV 데이터 이행용 (가장 안정적)
SQL (DDL) 테이블/시퀀스/인덱스
SQL (INSERT) 소량 데이터
ZIP 다수 파일 묶기

❌ 비추천

  • Excel 직접 생성 (대용량에서 위험)
  • JSON (DB 이행 목적에 부적합)

6️⃣ 여기서 반드시 분리해서 생각해야 할 점

❗ “조회”와 “변환”은 다른 책임이다

단계 책임
객체 목록 조회 Backend + Oracle
변환 Ora2Pg
파일 전달 Backend
선택 UI React

👉 이걸 섞으면 구조가 바로 무너진다.


7️⃣ 실무적으로 꼭 넣어야 하는 UX 설계 포인트

이건 개발자 관점에서 매우 중요하다.

화면에서 반드시 있어야 할 것

  • 객체 타입별 탭 (TABLE / VIEW / …)
  • 전체 선택 / 해제
  • 예상 건수 표시
  • “대용량 경고” 문구
  • 변환 중 상태 표시 (로그)

안 하면 생기는 문제

  • 전 테이블 선택
  • CSV 수십 GB 생성
  • 브라우저/서버 다운

8️⃣ 최종 논리 점검

  • Ora2Pg는 선택된 객체만 변환 가능
  • Oracle 객체 목록은 사전 조회 가능
  • CSV/SQL 파일 생성은 이미 검증된 기능
  • React UI와의 결합도 자연스러움

❌ 논리 충돌 없음
❌ 기술적 무리 없음


최종 요약

이 어플리케이션에서

  • 화면의 조회 버튼으로 Oracle 객체 목록을 불러오고
  • 사용자가 선택한 뒤
  • 파일 다운로드 버튼으로 CSV/SQL 등 변환 파일을 생성해 주는 구조

👉 완전히 가능하고, 오히려 정석적인 설계다.

다음 단계로 이어가면 딱 좋은 주제는:

  • Oracle 객체 조회 API 설계
  • ora2pg.conf 자동 생성 규칙
  • 대용량 CSV 다운로드 UX 설계
  • Job 기반 비동기 처리 구조
    👉 Job / Runner / Artifact 도메인 모델 설계
    👉 FastAPI 기준 오케스트레이터 코드 스켈레톤
    👉 “Job을 스레드로 할까, 프로세스로 할까?”
    👉 “Docker Job과 로컬 Job의 보안 차이”
반응형

댓글