昨天寫了 web三層架構的第一版,準確的說是三層架構的前期,頂多算是個二層架構,要慢慢完善。
第一版里,程序雖說能運行起來,但是有一個缺陷,就是里面的SQL語句,是使用的拼接字符進行執行。這樣安全系數很低,如果有心人的話,可能會SQL注入,重新拼接字符,然后篡改我們的數據庫內容,導致不可挽回的損失。
在第二版本,也就是這一版里,我對原來的SQL語句進行了重構,使用帶參數的SQL語句對數據庫進行操作,這樣做的好處是,無論用戶輸入的是什么格式的字符,SQL語句都會原封不動的把這些字符寫入到數據庫中,這樣就避免了有心人對字符進行拼接,導致數據庫出錯。
下面我用另一個小例子來說明防止SQL注入的核心代碼,在最后會給出我重構過的第一版程序,也就是今天要寫第二版程序:
這是DAO類中的insert方法:
1 public bool insert(string name, string sex, string salary) 2 { 3 bool flag = false; 4 5 SqlParameter[] paras = new 6 { 7 new SqlParameter("@name", name), 8 new SqlParameter("@sex", sex), 9 new SqlParameter("@salary", salary)10 };11 12 string sql = "insert into person ([name], sex, salary) values (@name, @sex, @salary)";13 14 if (sq.ExecuteNonQuery(sql, paras) > 0) //把SQL語句和SQL參數同時傳入SQLHelper的ExecuteNonQuery中執行。15 { //16 flag = true;17 }18 19 return flag;20 }
這是SQLHelper類中的ExecuteNonQuery方法:
1 public int ExecuteNonQuery(string sql, SqlParameter[] paras) 2 { 3 int result; 4 5 cmd = new SqlCommand(sql, getcon()); //創建SQLcommand對象cmd 6 7 cmd.Parameters.AddRange(paras); //在SQLcommand對象cmd中,添加參數。 8 //上面的這一句注釋,是自己的理解,如果理解錯了,請在評論區幫忙指正一下,先謝過。 9 result = cmd.ExecuteNonQuery(); //然后執行對象cmd,其中已經包含了SQL語句和要用的參數10 11 return result;12 }
上面是一個小例子,創建了一張表,然后向表里的 NAME SEX SALARY 三個字段中添加內容。
下面是第二版web三層架構程序:
SQLhelper助手類:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using System.Data; 8 using System.Data.SqlClient; 9 using System.Configuration; 10 11 namespace DAL 12 { 13 public class SQLHelper 14 { 15 SqlCommand cmd = null; 16 17 public string strcon() 18 { 19 string strcon = ConfigurationManager.ConnectionStrings["strcon"].ConnectionString; 20 21 return strcon; 22 } 23 24 public SqlConnection getcon() 25 { 26 SqlConnection con = new SqlConnection(strcon()); 27 28 if (con.State == ConnectionState.Closed) 29 { 30 con.Open(); 31 } 32 33 return con; 34 } 35 36 #region 執行增刪改查的SQL語句 37 /// <summary> 38 /// 執行增刪改查的SQL語句 39 /// </summary> 40 /// <param name="sql">要執行的SQL</param> 41 /// <returns>返回執行SQL語句后影響的行數</returns> 42 public int ExecuteNonQuery(string sql) 43 { 44 int res; 45 46 try 47 { 48 cmd = new SqlCommand(sql, getcon()); 49 50 res = cmd.ExecuteNonQuery(); 51 } 52 catch (Exception ex) 53 { 54 throw ex; 55 } 56 finally 57 { 58 if (getcon().State == ConnectionState.Open) 59 { 60 getcon().Close(); 61 } 62 } 63 64 return res; 65 } 66 #endregion 67 68 #region 執行帶參數的增刪改SQL語句 69 /// <summary> 70 /// 執行帶參數的增刪改SQL語句 71 /// </summary> 72 /// <param name="sql">要執行的SQL語句</param> 73 /// <param name="paras">傳入的參數</param> 74 /// <returns>返回受影響的行數</returns> 75 public int ExecuteNonQuery(string sql, SqlParameter[] paras)//上下兩個ExecuteNonQuery因為使用了方法的重載,其中參數不同,所以雖說都在調用ExecuteNonQuery,但是傳遞的參數的個數不同,系統會自動識別用哪一個ExecuteNonQuery方法。 76 { 77 int res; 78 79 cmd = new SqlCommand(sql, getcon());// 1 80 81 cmd.Parameters.AddRange(paras);// 2 84 85 res = cmd.ExecuteNonQuery(); 86 87 return res; 88 } 89 #endregion 90 91 #region 執行傳入的SQL查詢語句 92 /// <summary> 93 /// 執行傳入的SQL查詢語句 94 /// </summary> 95 /// <param name="sql">要執行的查詢SQL</param> 96 /// <returns>返回查詢SQL語句的數據集</returns> 97 public DataTable ExecuteQuery(string sql) 98 { 99 DataTable dt = new DataTable();100 101 //創建一個SqlCommand對象cmd,讓其連接數據庫,并指向sql語句。//自己理解,如果不對的話請在評論區指正,先謝過。102 cmd = new SqlCommand(sql, getcon());103 104 //執行cmd連接的數據庫.使用using后在執行完畢后,直接關閉sdr。不需要寫sdr.closed.105 using (SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))//如果使用 CommandBehavior.CloseConnection 參數,那么在代碼的結尾處就不需要寫 getcon().Close(),他會直接關閉。106 {107 dt.Load(sdr);// Load 這種方法適合于SqlDataReader。如果是SqlDataAdapter,則會用到 Fill 方法。108 }109 110 return dt;111 }112 #endregion113 114 #region 執行傳入帶參數的SQL查詢語句115 /// <summary>116 /// 執行傳入帶參數的SQL查詢語句117 /// </summary>118 /// <param name="sql">要執行的SQL語句</param>119 /// <param name="paras">傳入的參數</param>120 /// <returns>返回查詢的數據集</returns>121 public DataTable ExecuteQuery(string sql, SqlParameter[] paras)122 {123 DataTable dt = new DataTable();124 125 cmd = new SqlCommand("sql", getcon());126 127 cmd.Parameters.AddRange(paras);128 129 using (SqlDataReader sdr = cmd.ExecuteReader(CommandBehavior.CloseConnection))130 {131 dt.Load(sdr);132 }133 134 return dt;135 }136 #endregion137 }138 }
personDAO員工操作類:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using System.Data; 8 using System.Data.SqlClient; 9 10 namespace DAL 11 { 12 public class personDAO 13 { 14 SQLHelper sq = null; 15 16 public personDAO() 17 { 18 sq = new SQLHelper(); 19 } 20 21 #region 增加員工信息 22 /// <summary> 23 /// 增加員工信息 24 /// </summary> 25 /// <param name="name">要添加的員工姓名</param> 26 /// <param name="sex">要添加的員工性別</param> 27 /// <param name="salary">要添加的員工工資</param> 28 /// <returns>返回真假值:如果是真顯示添加成功,如果是假顯示添加失敗</returns> 29 public bool insert(string name, string sex, string salary) 30 { 31 bool flag = false; 32 33 SqlParameter[] paras = new SqlParameter[] 34 { 35 new SqlParameter("@name", name), 36 new SqlParameter("@sex", sex), 37 new SqlParameter("@salary", salary) 38 }; 39 40 string sql = "insert into person ([name], sex, salary) values (@name, @sex, @salary)";//記住,添加參數的時候,不需要 雙引號 或是 單引號。 41 42 if (sq.ExecuteNonQuery(sql, paras) > 0)//把sql語句和所用到參數數組,一起傳送到 ExecuteNonQuery 中去執行。 43 { 44 flag = true; 45 } 46 47 return flag; 48 } 49 #endregion 50 51 #region 刪除員工信息 52 /// <summary> 53 /// 刪除員工信息 54 /// </summary> 55 /// <param name="id">要刪除員工的id</param> 56 /// <returns>返回真假值:如果是真顯示刪除成功,如果是假顯示刪除失敗</returns> 57 public bool delete(string id) 58 { 59 bool flag = false; 60 61 SqlParameter[] paras = new SqlParameter[] 62 { 63 new SqlParameter("@id", id) 64 }; 65 66 string sql = "delete from person where id = @id";//記住,添加參數的時候,不需要 雙引號 或是 單引號。 67 68 if (sq.ExecuteNonQuery(sql, paras) > 0) 69
新聞熱點
疑難解答