Python – Script

在寫全端的專案的時候有遇到一個問題就是Next.js沒辦法跑DB2! ( IBM 公司開發的一款企業級關聯式資料庫管理系統RDBMS,以極高的效能著稱)

因此我的解法是透過 python 寫一個Script,有需要去DB2查詢時就只用指令執行此 python,python腳本回傳JSON即可~

這裡提供範例:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations

import sys
import io
import json
import os
# --- DB2 環境配置 ---
if os.name == 'nt':
    clidriver_path = r'C:\temp\clidriver\bin'
    if os.path.exists(clidriver_path):
        os.add_dll_directory(clidriver_path)
    # 強制 UTF-8 輸出,避免 Windows 轉碼錯誤

    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

def _build_conn_string() -> str:
    host = os.environ.get("DB2_HOST", "XXX.vghtpe.gov.tw").strip()
    port = os.environ.get("DB2_PORT", "3306").strip()
    database = os.environ.get("DB2_DATABASE", "DBHIS").strip()
    user = os.environ.get("DB2_USER", os.environ.get("DB2_UID", "TEST")).strip()
    password = os.environ.get("DB2_PASSWORD", os.environ.get("DB2_PWD", "TEST")).strip()

    return f"DATABASE={database};HOSTNAME={host};PORT={port};PROTOCOL=TCPIP;UID={user};PWD={password};"

# 用法: db2_vitals.py <histno> <caseno>
def main():

    histno = sys.argv[1].strip()
    caseno = sys.argv[2].strip()


    try:
        import ibm_db
        conn = ibm_db.connect(_build_conn_string(), "", "")
        sql = """
            SELECT 
                ERTTBP1, 
                ERTTBP2, 
                ERTTPR, 
                ERTTRR, 
                ERTTBT, 
                ERTTKG,
                ERTTS12
            FROM VGHLNXVG.ERTTAS5
            WHERE ERTTHIST = ?
            AND RIGHT(TRIM(ERTTBKEY), 8) = ? 
            WITH UR
        """
        
        stmt = ibm_db.prepare(conn, sql)
        ibm_db.bind_param(stmt, 1, histno)
        ibm_db.bind_param(stmt, 2, caseno)
        ibm_db.execute(stmt)
        
        row = ibm_db.fetch_assoc(stmt)

        if row:
            final_data = {
                "bp_s": str(row.get("ERTTBP1") or "").strip(),
                "bp_d": str(row.get("ERTTBP2") or "").strip(),
                "pr":   str(row.get("ERTTPR") or "").strip(),
                "rr":   str(row.get("ERTTRR") or "").strip(),
                "bt":   str(row.get("ERTTBT") or "").strip(),
                "bw":   str(row.get("ERTTKG") or "").strip(),
                "疼痛評估": str(row.get("ERTTS12") or "").strip(),
            }
            print(json.dumps({"success": True, "data": final_data}))
        else:
            print(json.dumps({"success": False, "error": 123}))
        ibm_db.close(conn)
        
    except Exception as e:
        # 發生錯誤時輸出詳細資訊到 stderr 並回傳失敗 JSON
        import traceback
        print(traceback.format_exc(), file=sys.stderr)
        print(json.dumps({"success": False, "error": str(e)}))
        sys.exit(1)

if __name__ == "__main__":
    main()Code language: JavaScript (javascript)

這裡解釋一些比較特殊的寫法以及為什麼要這樣寫:

註:之後有可能會要上Docker因此有些Linux的指令會先留著

標頭

  • #!/usr/bin/env python3:指定使用 Python 3 解釋器執行。在linux下會被執行。
  • # -*- coding: utf-8 -*-:宣告檔案編碼為 UTF-8,確保中文字元顯示正確。
  • from __future__ import annotations:啟用Type Hints(型別提示):-> str:
    • 如果函數定義回傳 str,結果回傳數字,IDE 會跟據此偵測錯誤。
  • import sys, io, json, os:匯入標準函式庫,處理系統參數、輸出流、JSON 格式與作業系統功能。

DB2 環境配置

  • if os.name == 'nt'::判斷是否在 Windows 環境下。
    • os.add_dll_directory(...):告訴 Windows 哪裡可以找到 DB2 的連接驅動程式(clidriver)。
    • sys.stdout 強制將標準輸出 (stdout) 與錯誤輸出 (stderr) 設定為 UTF-8 編碼,防止在 Windows CMD 中出現亂碼。

main

  • 連接資料庫
    • import ibm_db:在此階段才匯入 DB2 驅動,確保環境設定已完成。
    • ibm_db.connect(...):建立連線。
  • 執行 SQL
    • 使用 ? 佔位符(Parameterized Query),這能有效防止 SQL Injection(資料隱碼攻擊)
    • WITH UR:意指 Uncommitted Read,在查詢 DB2 時允許讀取尚未提交的資料,可提升查詢效能且減少鎖定衝突。為DB2特有寫法。
    • 使用 bind_param 寫入資料,資料庫會將 user_input 視為純粹的「資料(Data)」,而不是「SQL 指令」,防止SQL注入。
  • 資料處理
    • ibm_db.fetch_assoc(stmt):將查詢到的結果轉為關聯式陣列(字典)。
    • 若有結果,將欄位名稱(如 ERTTBP1)對應到更友善的 JSON Key(如 bp_s 代表血壓收縮壓)。
    • json.dumps(...):將結果轉為 JSON 字串輸出。
  • 例外處理 (except)
    • 若查詢失敗,輸出錯誤堆疊資訊(traceback)到錯誤流,並輸出 JSON 格式的錯誤訊息,方便呼叫端捕捉失敗狀態。