存儲過程將業務邏輯下沉到資料庫層,C 語言透過 CALL 語句調用,利用 CLIENT_MULTI_STATEMENTS 支援多結果集,並透過用戶變數 @out_param 獲取 OUT 參數。本文提供完整可編譯範例:建表、存儲過程、C 代碼、編譯執行。
選課記錄表 sc:cno(課程號)、sno(學號)、ordinary_score(平時分)、last_score(卷面分)、all_score(總分)。
CREATE TABLE sc ( cno VARCHAR(8) NOT NULL, sno VARCHAR(8) NOT NULL, ordinary_score INT, last_score INT, all_score INT );
輸入:平時分 x、卷面分 y、平時分權重 pert、學號 s、課程號 c。
輸出:OUT 參數 t (總分或錯誤碼 -1/-2)。
DELIMITER // CREATE PROCEDURE cal_grade( IN x INT, IN y INT, OUT t INT, IN pert FLOAT, IN s VARCHAR(8), IN c VARCHAR(8) ) LABEL_PROC: BEGIN IF (x < 0 || x > 100) THEN SET t = -1; LEAVE LABEL_PROC; END IF; IF (y < 0 || y > 100) THEN SET t = -2; LEAVE LABEL_PROC; END IF; SET t = ROUND(x * pert + y * (1 - pert)); UPDATE sc SET ordinary_score = x, last_score = y WHERE sno = s AND cno = c; END LABEL_PROC // DELIMITER ;
#include#include "mysql.h" int main() { MYSQL *conn; MYSQL_RES *res; MYSQL_ROW row; char buf[100]; conn = mysql_init(NULL); // 關鍵:CLIENT_MULTI_STATEMENTS 允許 CALL + 後續 SELECT @t conn = mysql_real_connect(conn, "localhost", "root", "root", "test", 0, NULL, CLIENT_MULTI_STATEMENTS); if (!conn) { fprintf(stderr, "Connect failed: %s\n", mysql_error(conn)); return 1; } // 呼叫存儲過程,OUT 參數寫入用戶變數 @t sprintf(buf, "CALL cal_grade(%d, %d, @t, %f, '%s', '%s')", 10, 10, 0.3, "123", "456"); if (mysql_query(conn, buf)) { fprintf(stderr, "CALL failed: %s\n", mysql_error(conn)); mysql_close(conn); return 1; } // 獲取 OUT 參數 if (mysql_query(conn, "SELECT @t")) { fprintf(stderr, "SELECT @t failed: %s\n", mysql_error(conn)); mysql_close(conn); return 1; } res = mysql_store_result(conn); if (res) { row = mysql_fetch_row(res); if (row && row[0]) { if (strcmp(row[0], "-1") == 0) printf("平時分不在範圍內\n"); else if (strcmp(row[0], "-2") == 0) printf("卷面分不在範圍內\n"); else printf("總分為: %s\n", row[0]); } mysql_free_result(res); } mysql_close(conn); return 0; }
gcc -o call_proc call_proc.c -I/usr/local/include/mysql -L/usr/local/lib/mysql -lmysqlclient -lz -lm ./call_proc
| 技術點 | 說明 |
|---|---|
| CLIENT_MULTI_STATEMENTS | 連線參數必須帶上,否則 CALL 後無法執行後續 SELECT @t,報錯 PROCEDURE can't return a result set in the given context |
| OUT 參數獲取 | MySQL 存儲過程 OUT 參數寫入用戶變數 @var,需額外 SELECT @var 讀取 |
| 錯誤碼設計 | 約定負數為錯誤碼 (如 -1, -2),正數為正常業務返回值 |
| 標籤跳出 | 存儲過程中 LEAVE LABEL 實現提前返回,避免深層巢狀 IF |
| 參數模式 | IN (預設, 傳入)、OUT (傳出)、INOUT (雙向) |
mysql_stmt_prepare("CALL cal_grade(?, ?, @t, ?, ?, ?)") 綁定參數,防注入、提升重複調用效能。call_proc(proc_name, in_params..., out_param_names...) 函數,簡化業務代碼。mysql_error()、mysql_sqlstate()。掌握「CALL + SELECT @out」雙語句模式與 CLIENT_MULTI_STATEMENTS 連線選項,即可在 C/C++ 系統中高效複用資料庫端業務邏輯。