반응형
다만 “어디까지 자동으로 되고, 어디부터는 설계가 필요한지”를 명확히 구분해야 한다.
아래를 단계별로 차근차근 정리할게.
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줄)
- 변환 로직은 도구에 위임
- 백엔드는 순서와 상태만 관리
- 실행 환경은 추상화
코드 레벨에서 보면 이렇게 달라진다
❌ 잘못된 백엔드 설계
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 스레드 종료
- 메모리 해제
❌ 자동 파괴가 깨지는 경우
- 전역 변수에 저장
- 캐시(redis 등)에 저장
- 파일로 기록
- 로그에 출력
- Job 종료 후 재사용
- 예외 발생 시 참조 유지
👉 이러면:
- 프로세스 살아 있는 동안 계속 남아 있음
- 심지어 메모리 덤프 시 노출 가능
✔ 반드시 지켜야 할 설계 원칙
① 접속 정보는 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의 보안 차이”
반응형
'실험실 > db이행' 카테고리의 다른 글
| 이슈 업무범위 ddl까지 vs data 이행까지 (0) | 2026.01.15 |
|---|---|
| 이슈 (1) | 2026.01.15 |
| 실행모델, Job구조, 상태모델, 보안모델, 결과물 스펙 등 결정사항 (0) | 2026.01.14 |
| 언어선택의 기준 (1) | 2026.01.14 |
| ORACLE -> PostgreSQL (0) | 2026.01.12 |
댓글