标签:
昨天写了 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 #endregion 113 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 #endregion 137 } 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 { 70 flag = true; 71 } 72 73 return flag; 74 } 75 #endregion 76 77 #region 更改员工信息 78 /// <summary> 79 /// 更改员工信息 80 /// </summary> 81 /// <param name="id">要更改的员工编号</param> 82 /// <param name="name">要更改的员工姓名</param> 83 /// <param name="sex">要更改的员工性别</param> 84 /// <param name="salary">要更改的员工工资</param> 85 /// <returns>返回真假值:如果是真显示更改成功,如果是假显示更改失败</returns> 86 public bool update(string id, string name, string sex, string salary) 87 { 88 bool flag = false; 89 90 SqlParameter[] paras = new SqlParameter[]//创建参数数组 91 { 92 new SqlParameter("@id", id),//我的理解:对参数数组赋值 93 new SqlParameter("@name", name), 94 new SqlParameter("@sex", sex), 95 new SqlParameter("@salary", salary) 96 }; 97 98 //使用参数数组 99 string sql = "update person set [name] = @id, sex = @name, salary = @sex where id = salary";//记住,添加参数的时候,不需要 双引号 或是 单引号。 100 101 if (sq.ExecuteNonQuery(sql, paras) > 0) 102 { 103 flag = true; 104 } 105 106 return flag; 107 } 108 #endregion 109 110 #region 判断员工姓名是否重复 111 /// <summary> 112 /// 判断员工姓名是否重复 113 /// </summary> 114 /// <param name="name">要进行判断的员工姓名</param> 115 /// <returns>返回真假值:如果是真代表重复,如果是假进行添加</returns> 116 public bool repeat(string name) 117 { 118 bool flag = false; 119 120 SqlParameter[] paras = new SqlParameter[] 121 { 122 new SqlParameter("@name", name) 123 }; 124 125 string sql = "select * from person where [name] = @name";//记住,添加参数的时候,不需要 双引号 或是 单引号。 126 127 #region 下面这样写的话,还要重新建立一张虚拟表,如果直接用下面的方法,进行行数的判断就不需要建立。 128 //DataTable dt = sq.ExecuteQuery(sql); 129 130 //if (dt.Rows.Count > 0)//dt.Rows.Count 这个方法是检查返回的虚拟表中是不是有数据,如果有的话则行数不为零。如果没有的话则行数为零。 131 //{ 132 // flag = true; 133 //} 134 #endregion 135 136 if (sq.ExecuteQuery(sql, paras).Rows.Count > 0)//dt.Rows.Count 这个方法是检查返回的虚拟表中是不是有数据,如果有的话则行数不为零。如果没有的话则行数为零。 137 { 138 flag = true; 139 } 140 141 return flag; 142 } 143 #endregion 144 } 145 }
上面就是重构的第一版的代码,也就是第二版,其中如果有错误的地方,请在评论区帮忙指正,先谢过了大家。
标签:
原文地址:http://www.cnblogs.com/KTblog/p/4189859.html