DB2 存儲過程 (SQL PL / PL/SQL) 開發常面臨:樣板代碼重複 (錯誤處理、日誌、事務控制)、參數映射繁瑣、部署腳本手工維護、版本升級遷移困難、缺乏單元測試框架。通過腳本化 (Shell/Python/Groovy) + 模板引擎 (Jinja2/Velocity/Mustache) + CI/CD 流水線,可實現「配置驅動生成、一鍵部署、自動測試、版本化管理」。
name: "process_order"
schema: "APP"
params:
- {name: "p_order_id", type: "BIGINT", mode: "IN"}
- {name: "p_status", type: "VARCHAR(20)", mode: "OUT"}
- {name: "p_msg", type: "VARCHAR(200)", mode: "OUT"}
logic: |
-- 業務邏輯片段 (SQL PL)
DECLARE v_count INT;
SELECT COUNT(*) INTO v_count FROM orders WHERE id = p_order_id;
IF v_count = 0 THEN
SET p_status = 'NOT_FOUND'; SET p_msg = 'Order not found'; RETURN;
END IF;
UPDATE orders SET status='PROCESSING' WHERE id = p_order_id;
-- ... 更多邏輯
SET p_status = 'SUCCESS'; SET p_msg = 'OK';
grants: ["APP_ROLE"]
tests:
- {input: {p_order_id: 999}, expect: {p_status: "NOT_FOUND"}}
- {input: {p_order_id: 1001}, expect: {p_status: "SUCCESS"}}
{# template/sp_template.sql.j2 #}
CREATE OR REPLACE PROCEDURE {{schema}}.{{name}} (
{% for p in params %} {{p.mode}} {{p.name}} {{p.type}}{% if not loop.last %},{% endif %}
{% endfor %}
)
LANGUAGE SQL
SPECIFIC {{schema}}.{{name}}
NOT DETERMINISTIC
MODIFIES SQL DATA
CALLED ON NULL INPUT
INHERIT SPECIAL REGISTERS
BEGIN
DECLARE SQLSTATE CHAR(5);
DECLARE v_err_msg VARCHAR(1000);
-- 標準錯誤處理塊
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 v_err_msg = MESSAGE_TEXT;
SET {{out_param('p_msg')}} = 'ERROR: ' || v_err_msg;
SET {{out_param('p_status')}} = 'FAILED';
RESIGNAL; -- 可選:拋給調用者
END;
{{logic | indent(2)}}
END@
模板中封裝 `EXECUTE IMMEDIATE` 安全構建函數,防止注入:
{% macro safe_exec(sql_template, params) %}
DECLARE v_stmt VARCHAR(32000);
SET v_stmt = {{sql_template | tojson}}; -- 模板字符串
{% for p in params %}
SET v_stmt = REPLACE(v_stmt, ':{p}', CAST({p} AS VARCHAR(1000)));
{% endfor %}
EXECUTE IMMEDIATE v_stmt;
{% endmacro %}
| 指標 | 手工開發 | 腳本化生成 | 提升 |
|---|---|---|---|
| 新增 SP 耗時 | 2-4 小時 | 10-30 分鐘 | 80%+ |
| 樣板代碼錯誤率 | ~5% | ~0% | 消除 |
| 部署一致性 | 人工差異 | 100% 一致 | 標準化 |
| 回滾時間 | 30 分鐘 | < 1 分鐘 | 自動化 |
| 測試覆蓋率 | 低 (手工) | 高 (元數據驅動) | 體系化 |