반응형

파이썬, FastAPI Oracle 연동 예제 2 (Pooling 모드 선택)

 

정리. 수알치 오상문 

 

먼저 fastapi 등 관련 패키지들이 설치되어 있다고 가정하겠습니다.

 

예제 진행을 위해서 oracle 19c를 설치했습니다(오라클 사이트에서 다운로드 후 설치).

파이썬(FastAPI)와 oracle 연결은 cx_Oracle 패키지를 이용합니다(pip install cx_oracle).

그리고 Oracle Instance Client도 오라클 사이트에서 다운로드 하여 설치해야 합니다. 

 

[참고] DB 연결 구조

파이썬(FastAPI) <--> cx_Oracle <-->  Oracle Instance Client <--> Oracle DBMS

 

접속 예제는 다음과 같은데 연결하는 구조 파악에 참고하세요.

실제로 실행하려면 다른 작업들도 있는데 생략되어 있습니다.

이전 예제와 다른 부분은 DB 서버에서 Session Pooling 모드 사용여부입니다. 

 

[참고] 오라클 세션 풀링 

https://docs.oracle.com/en/database/oracle/oracle-database/18/lnoci/session-and-connection-pooling.html#GUID-FD512A09-1A33-424B-AD4D-728956AFDBD8

 

Pooling 모드를 사용하면 DB 서버의 메모리 부하를 줄여준다고 합니다.

다음은 코드는 일반 연결과 세션 풀링을 이용하는 연결 예를 보여줍니다.

 

from typing import Optional
from fastapi import FastAPI, APIRouter
from pydantic import BaseModel, Field
from fastapi.encoders import jsonable_encoder
import os
import cx_Oracle

# DB 운영 모드: "NORMAL" or "POOL"
DBMODE = "POOL"


# oracle instance-client 환경 및 접속 정보
user = ["c##dbuser", "a1b2c3d4"]      # DB 사용자 계정은 c##dbuser, 비밀번호는 a1b2c3d4 지정 
LOCATION = r"C:\instantclient_21_3"  # DB 디렉터리 지정 
os.environ["PATH"] = LOCATION + ";" + os.environ["PATH"]  # 환경변수 등록

# oracle DB 연결
if DBMODE == "POOL":
    try:
        pool = cx_Oracle.SessionPool(user[0], user[1], "127.0.0.1:1521/orcl") 
             min=10, max=100, increment=5)
        cursor = connection.cursor()
    except Exception as err:
        print("DB ERROR: ", err)
        sys.exit(1)
else:  # DBMODE=="NORMAL"
    try:
        connect = cx_Oracle.connect(user[0], user[1], "127.0.0.1:1521/orcl")
        cursor = connect.cursor()
    except Exception as err:
        print("DB ERROR: ", err)
        sys.exit(1)

# FastAPI 서버 객체 생성
app = FastAPI()
# fastapi 서버 디렉터리로 이동하고 
# uvicorn main:app --reload --host=0.0.0.0 --port=80 
# (Linux는 sudo uvicorn main:app --reload --host=0.0.0.0 --port=80)  

# 스웨거에 도움말 넣기 옵션: name(제목), description(설명)
@app.get("/", name='루트 접속 처리', description='기본 루트 접속시 처리 API입니다.') 
async def root():
  return {"Service": "REST-API 0.1", 
          "API Test": ".../docs", 
          "API Help": ".../redoc", 
          "Message": "Have a nice day!"}    

# Oracle 19c 테스트 ----------------------  

@app.get("/oracle/")  # 직원 목록을 제공한다.
def oracle():
  cursor.execute("select * from emp")  # emp 테이블에서 내용을 가져온다.
  data = {}
  for n, row in enumerate(cursor):
    data[n] = jsonable_encoder(row) 
        
  return data


class JobData(BaseModel):   # 직군 모델 설정 (POST로 받기) 
  job: str     # 직군


@app.post("/oracle/job")  # 직군으로 검색하기  
def oracle_job(what: JobData):
  # docs에 접속해서 "SALESMAN"으로 요청해보자.  
  cursor.execute("""select * from emp where emp.job = :whatjob""", whatjob=what.job)
  data = {}
  for n, row in enumerate(cursor):
    data[n] = jsonable_encoder(row) 
        
  return data

 

 

[참고] 오라클에는 emp 테이블 구조를 만들고 예제 데이터를 입력했다. 

CREATE TABLE emp 

    empno       NUMBER(4) NOT NULL,
    ename       VARCHAR2(10),
    job         VARCHAR2(9),
    mgr         NUMBER(4),
    hiredate    DATE,
    sal         NUMBER(7,2),
    comm        NUMBER(7,2),
    deptno      NUMBER(2)
);

 

ALTER TABLE emp ADD CONSTRAINT emp_pk PRIMARY KEY (empno);
COMMENT ON TABLE emp IS '사원정보';
COMMENT ON COLUMN emp.empno IS '사원번호';
CREATE INDEX emp_idx01 ON emp(job, deptno);
COMMENT ON COLUMN emp.empno IS '사원번호';
COMMENT ON COLUMN emp.ename IS '성명';
COMMENT ON COLUMN emp.job IS '직군';
COMMENT ON COLUMN emp.mgr IS '직속상사';
COMMENT ON COLUMN emp.hiredate IS '입사일';
COMMENT ON COLUMN emp.sal IS '급여';
COMMENT ON COLUMN emp.comm IS '보너스';
COMMENT ON COLUMN emp.deptno IS '부서코드';

INSERT INTO emp VALUES(7839, 'KING', 'PRESIDENT', NULL, TO_DATE('1981-11-17', 'yyyy-mm-dd'), 5000, NULL, 10);
INSERT INTO emp VALUES(7698, 'BLAKE', 'MANAGER', 7839, TO_DATE('1981-05-01', 'yyyy-mm-dd'), 2850, NULL, 30);
INSERT INTO emp VALUES(7782, 'CLARK', 'MANAGER', 7839, TO_DATE('1981-06-09', 'yyyy-mm-dd'), 2450, NULL, 10);
INSERT INTO emp VALUES(7566, 'JONES', 'MANAGER', 7839, TO_DATE('1981-04-02', 'yyyy-mm-dd'), 2975, NULL, 20);
INSERT INTO emp VALUES(7788, 'SCOTT', 'ANALYST', 7566, TO_DATE('1987-04-19', 'yyyy-mm-dd'), 3000, NULL, 20);
INSERT INTO emp VALUES(7902, 'FORD', 'ANALYST', 7566, TO_DATE('1981-12-03', 'yyyy-mm-dd'), 3000, NULL, 20);
INSERT INTO emp VALUES(7369, 'SMITH', 'CLERK', 7902, TO_DATE('1980-12-17', 'yyyy-mm-dd'), 800, NULL, 20);
INSERT INTO emp VALUES(7499, 'ALLEN', 'SALESMAN', 7698, TO_DATE('1981-02-20', 'yyyy-mm-dd'), 1600, 300, 30);
INSERT INTO emp VALUES(7521, 'WARD', 'SALESMAN', 7698, TO_DATE('1981-02-22', 'yyyy-mm-dd'), 1250, 500, 30);
INSERT INTO emp VALUES(7654, 'MARTIN', 'SALESMAN', 7698, TO_DATE('1981-09-28', 'yyyy-mm-dd'), 1250, 1400, 30);
INSERT INTO emp VALUES(7844, 'TURNER', 'SALESMAN', 7698, TO_DATE('1981-09-08', 'yyyy-mm-dd'), 1500, 0, 30);
INSERT INTO emp VALUES(7876, 'ADAMS', 'CLERK', 7788, TO_DATE('1987-05-23', 'yyyy-mm-dd'), 1100, NULL, 20);
INSERT INTO emp VALUES(7900, 'JAMES', 'CLERK', 7698, TO_DATE('1981-12-03', 'yyyy-mm-dd'), 950, NULL, 30);
INSERT INTO emp VALUES(7934, 'MILLER', 'CLERK', 7782, TO_DATE('1982-01-23', 'yyyy-mm-dd'), 1300, NULL, 10);

--------------------------------------------------------------------------------------------

<이상>

반응형

+ Recent posts