MySQL 預存程序或批次 SQL 可一次返回多個結果集。C# 中需結合 MySqlDataReader 的 NextResult() 與 MySqlDataAdapter.FillAsync() 依序讀取每個結果集並填入 DataTable。
NextResult() 移動到下一個結果集,返回 true 表示存在。FillAsync(DataTable, IDataReader) 將當前結果集資料填入 DataTable。using System;
using System.Collections.Generic;
using System.Data;
using System.Threading;
using MySql.Data.MySqlClient;
public struct SqlParam {
public string Name;
public object Value;
public SqlParam(string n, object v) { Name = n; Value = v; }
}
public class MySqlHelper {
private readonly MySqlConnection _conn;
public MySqlHelper(string connStr) { _conn = new MySqlConnection(connStr); }
///
/// 執行預存程序或批次 SQL,返回多個 DataTable 列表
///
public List<DataTable> ExecuteMultipleResults(string spName, List<SqlParam> parameters) {
var tables = new List<DataTable>();
using (var cmd = new MySqlCommand(spName, _conn)) {
cmd.CommandType = CommandType.StoredProcedure;
foreach (var p in parameters)
cmd.Parameters.AddWithValue(p.Name, p.Value);
_conn.Open();
using (var reader = cmd.ExecuteReader()) {
var adapter = new MySqlDataAdapter();
var cts = new CancellationTokenSource(); // 可選:支援取消
bool hasMore = true;
while (hasMore) {
var dt = new DataTable();
// 同步等待填充完成;生產環境建議改用 await FillAsync
adapter.FillAsync(dt, reader).Wait(cts.Token);
tables.Add(dt);
hasMore = reader.NextResult(); // 移至下一結果集
}
}
}
return tables;
}
}
var helper = new MySqlHelper("Server=localhost;Database=test;Uid=root;Pwd=123456;");
var pars = new List<SqlParam> { new SqlParam("startPage", 0), new SqlParam("pageSize", 10) };
List<DataTable> results = helper.ExecuteMultipleResults("sp_get_posters", pars);
// results[0] -> SELECT COUNT(*) FROM poster;
// results[1] -> SELECT PosterID, PostTime, Title ... LIMIT ...
Console.WriteLine("總筆數:" + results[0].Rows[0][0]);
foreach (DataRow row in results[1].Rows)
Console.WriteLine($"{row["PosterID"]}\t{row["PostTime"]}\t{row["Title"]}");
MySqlConnection 需預先建立並開啟,讀取完畢自動關閉(using 區塊)。await adapter.FillAsync(dt, reader, cancellationToken) 避免阻塞執行緒。SqlParam 結構體,實際專案可直接用 MySqlParameter 集合。DataTable 需跨序列化邊界,注意 DataTable.RemotingFormat = SerializationFormat.Binary 可減小體積。MySqlDataAdapter.FillAsync 內部透過反射呼叫 DataTable.Load(IDataReader),而 MySqlDataReader 實作 IDataReader,NextResult() 推進內部結果集游標。兩者配合即可流式處理多結果集,記憶體佔用僅與單一結果集大小成正比。