字串拼接 SQL 是 SQL 注入攻擊的首要原因。SqlParameter 提供:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Configuration;
using System.Web.UI;
namespace ParaMeter {
public partial class Test : Page {
private string connectionStr;
private SqlConnection conn;
protected void Page_Load(object sender, EventArgs e) {
// 實務建議:從 web.config 讀取
// connectionStr = ConfigurationManager.ConnectionStrings["MyDb"].ConnectionString;
connectionStr = "Server=10.11.43.189\\SQL2008;Database=OA_WEB_DB;User ID=sa;Password=123456;";
conn = new SqlConnection(connectionStr);
}
protected void Button1_Click(object sender, EventArgs e) {
// 1. 參數化 SQL
StringBuilder sql = new StringBuilder();
sql.Append("INSERT INTO [OA_WEB_DB].[dbo].[OA_RT_FileType] ([FileTypeName], [Deleted])");
sql.Append(" VALUES (@fileName, @delete)");
// 2. 定義參數陣列(指定型別、長度)
SqlParameter[] parameters = {
new SqlParameter("@fileName", SqlDbType.NVarChar, 100),
new SqlParameter("@delete", SqlDbType.Bit)
};
// 3. 指派值
parameters[0].Value = "文件類型";
parameters[1].Value = false;
// 4. 執行並處理結果
bool success = ExecuteNonQuery(sql.ToString(), parameters);
Label1.Text = success ? "插入成功" : "插入失敗";
}
///
/// 執行增刪改(非查詢)參數化命令
///
private bool ExecuteNonQuery(string sqlText, params SqlParameter[] cmdParms) {
using (SqlCommand cmd = new SqlCommand()) {
try {
PrepareCommand(cmd, conn, null, sqlText, cmdParms);
int rows = cmd.ExecuteNonQuery();
return rows > 0;
}
catch (SqlException ex) {
// 實務:記錄 ex.Number, ex.Message, ex.StackTrace 至 Log
// 常見錯誤碼:2627 (PK違規), 547 (FK違規), 2601 (唯一索引違規)
return false;
}
}
}
///
/// 統一命令準備:開啟連線、指派參數、設定命令型別
///
private void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans,
string cmdText, SqlParameter[] cmdParms) {
if (conn.State != ConnectionState.Open) conn.Open();
cmd.Connection = conn;
cmd.CommandText = cmdText;
cmd.CommandType = CommandType.Text; // 或 StoredProcedure
if (trans != null) cmd.Transaction = trans;
if (cmdParms != null) {
foreach (SqlParameter p in cmdParms) {
// 處理 null 值:輸入/輸出入參數若為 null 轉 DBNull.Value
if ((p.Direction == ParameterDirection.Input || p.Direction == ParameterDirection.InputOutput)
&& p.Value == null) {
p.Value = DBNull.Value;
}
cmd.Parameters.Add(p);
}
}
}
}
}
| 實踐 | 代碼體現 | 效益 |
|---|---|---|
| 明確指定 SqlDbType 與 Size | new SqlParameter("@name", SqlDbType.NVarChar, 50) | 避免隱性轉換導致索引失效、計畫快取碎片化 |
| 使用 using 區塊管理 SqlCommand | using (SqlCommand cmd = new SqlCommand()) | 確保 Dispose 釋放非受控資源 |
| 連線開啟集中在 PrepareCommand | if (conn.State != ConnectionState.Open) conn.Open(); | 避免重複開啟、支援交易 |
| null 值轉 DBNull.Value | if (p.Value == null) p.Value = DBNull.Value; | 避免「參數值不可為 null」例外 |
| 捕獲 SqlException 並記錄錯誤碼 | catch (SqlException ex) { Log(ex.Number, ex.Message); } | 依錯誤碼給予用戶精確提示(如重複、外鍵衝突) |
| 連接字串放 web.config | ConfigurationManager.ConnectionStrings["name"] | 部署環境隔離、加密區段保護密碼 |
| 考慮連線池:預設啟用 | 連接字串 Pooling=true; Min Pool Size=5 | 高併發效能 |
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "usp_InsertFileType";
SqlParameter[] spParams = {
new SqlParameter("@FileTypeName", SqlDbType.NVarChar, 100) { Value = "文件類型" },
new SqlParameter("@Deleted", SqlDbType.Bit) { Value = false },
new SqlParameter("@NewId", SqlDbType.Int) { Direction = ParameterDirection.Output } // 輸出參數
};
ExecuteNonQuery(spParams); // 同一個方法支援
int newId = (int)spParams[2].Value; // 取得輸出值
// 使用 SqlBulkCopy 大量插入(DataTable 來源)
using (SqlBulkCopy bulk = new SqlBulkCopy(conn)) {
bulk.DestinationTableName = "OA_RT_FileType";
bulk.ColumnMappings.Add("FileTypeName", "FileTypeName");
bulk.ColumnMappings.Add("Deleted", "Deleted");
bulk.WriteToServer(dataTable); // dataTable 為來源資料
}
@fileName,參數建立用 @filename(大小寫不敏感但建議一致)。NVarChar 不給 Size 預設 -1(MAX),不同長度產生不同計畫。cmd.Parameters.Clear()。using (SqlTransaction trans = conn.BeginTransaction()) { ... trans.Commit(); }。新專案建議使用 Entity Framework Core / Dapper:
context.FileTypes.Add(new FileType { Name = "文件類型", Deleted = false }); await context.SaveChangesAsync();(自動參數化、LINQ、遷移)。conn.Execute("INSERT INTO FileType (Name, Deleted) VALUES (@Name, @Deleted)", new { Name = "文件類型", Deleted = false });(輕量、高效、自動參數化)。但理解 SqlParameter 底層機制對除錯、效能調校、舊系統維護仍至關重要。