首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# ADO.NET 插入/更新資料庫最佳實踐:參數化查詢與 SQL 注入防範

     編輯:程式設計綜合問答

原始碼問題分析

提供的程式碼存在嚴重安全與維護性問題:

  1. 字串拼接 SQL:直接拼接 `textBox.Text` 導致 SQL Injection 風險。
  2. 重複開關連線:多次 `Open()`/`Close()` 造成效能損耗與連線洩漏風險。
  3. 邏輯混雜:查詢、插入、更新混在同一方法,難以測試。
  4. 命名不規範:中文欄位名、變數名 `sql1`/`sql2` 降低可讀性。

重構版本:參數化查詢 + 單一連線 + 事務

using System;
using System.Data.SqlClient;
using System.Windows.Forms;

public void SaveCourse(string courseId, string courseName) {
    if (string.IsNullOrWhiteSpace(courseId) || string.IsNullOrWhiteSpace(courseName)) {
        MessageBox.Show("請輸入課程號和課程名!");
        return;
    }

    const string connStr = "Server=.;Database=Students;Integrated Security=True;";
    const string checkSql = "SELECT COUNT(1) FROM Course WHERE CourseId = @Id OR CourseName = @Name";
    const string insertSql = "INSERT INTO Course (CourseId, CourseName) VALUES (@Id, @Name)";
    const string updateSql = "UPDATE Course SET CourseName = @Name WHERE CourseId = @Id";

    using (var conn = new SqlConnection(connStr))
    using (var cmd = conn.CreateCommand()) {
        conn.Open();
        using (var tran = conn.BeginTransaction()) {
            cmd.Transaction = tran;
            try {
                // 檢查是否存在
                cmd.CommandText = checkSql;
                cmd.Parameters.Clear();
                cmd.Parameters.AddWithValue("@Id", courseId);
                cmd.Parameters.AddWithValue("@Name", courseName);
                int exists = (int)cmd.ExecuteScalar();

                if (exists > 0) {
                    var result = MessageBox.Show("課程已存在,是否更新?", "確認", 
                        MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                    if (result == DialogResult.OK) {
                        cmd.CommandText = updateSql;
                        cmd.Parameters.Clear();
                        cmd.Parameters.AddWithValue("@Id", courseId);
                        cmd.Parameters.AddWithValue("@Name", courseName);
                        cmd.ExecuteNonQuery();
                        MessageBox.Show("更新成功!");
                    }
                } else {
                    cmd.CommandText = insertSql;
                    cmd.Parameters.Clear();
                    cmd.Parameters.AddWithValue("@Id", courseId);
                    cmd.Parameters.AddWithValue("@Name", courseName);
                    cmd.ExecuteNonQuery();
                    MessageBox.Show("新增成功!");
                }
                tran.Commit();
            } catch (Exception ex) {
                tran.Rollback();
                MessageBox.Show("操作失敗:" + ex.Message);
            }
        }
    }
}

關鍵改進點

原寫法改進寫法效益
字串拼接 SQL參數化 `@Id`, `@Name`防 SQL Injection、計畫快取重用
多次 Open/Close`using` 區塊自動管理連線生命週期資源釋放確定、程式碼簡潔
無事務`BeginTransaction` / `Commit` / `Rollback`資料一致性保障
中文欄位名英文欄位名 (CourseId, CourseName)跨平台相容、維護性高

進階建議

  • 採用 Dapper / Entity Framework Core 等 ORM 簡化資料存取層。
  • 將資料庫邏輯移至 Repository 類別,UI 層僅負責呼叫。
  • 啟用連線池(ADO.NET 預設開啟),避免頻繁建立物理連線。

參考資源

C# 參數化查詢詳細教學:C# SQL 參數化查詢完整範例

總結

「參數化查詢」是 ADO.NET 開發的鐵律,「using + 事務」是資源管理的標準模式。重構後的程式碼更安全、更易讀、更易維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved