| 特性 | DataReader | DataSet |
|---|---|---|
| 連線模式 | 連線導向,需保持開啟 | 離線導向,讀完即關閉 |
| 資料流向 | 唯讀、單向、逐列 | 可讀寫、隨機存取、支援關聯 |
| 記憶體佔用 | 極低(單列緩衝) | 較高(全量載入記憶體) |
| 效能 | 快,適合大量資料串流 | 較慢,適合中小量資料多次操作 |
| 建立方式 | IDbCommand.ExecuteReader() | DbDataAdapter.Fill() |
| 適用場景 | 報表產生、大量資料匯出、單向綁定 | 複雜關聯查詢、離線編輯、多控制項共用資料 |
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand("SELECT * FROM News", conn))
{
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read()) // 唯一的讀取方式:逐列向前
{
Response.Write(dr["Title"] + "<br/>");
}
} // dr.Dispose() 自動關閉連線
}
DataSet ds = new DataSet();
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM News", conn))
{
da.Fill(ds); // 一次性填入記憶體,連線自動關閉
}
// 後續可任意操作:篩選、排序、關聯、寫回資料庫
DataView dv = ds.Tables[0].DefaultView;
dv.RowFilter = "Category='Sports'";
GridView1.DataSource = dv;
GridView1.DataBind();
dr.GetInt32(0) 比 dr["Id"] 快。int idx = dr.GetOrdinal("Title"); 僅呼叫一次,迴圈內重複使用。GetString、GetInt32、GetDateTime 避免裝箱/拆箱。int titleIdx = dr.GetOrdinal("Title");
int idIdx = dr.GetOrdinal("Id");
while (dr.Read())
{
Response.Write(dr.GetInt32(idIdx) + ": " + dr.GetString(titleIdx) + "<br/>");
}
DataSet 填滿後即斷開連線,**會釋放資料庫鎖定**;若在交易中使用 DataSet,需注意交易範圍不可過大,否則易造成並發衝突。DataReader 在讀取期間持續持有鎖定,長時間未關閉會阻塞其他寫入。