C#连接SQL-Server数据库超详细讲解以及防SQL注入
C#连接SQL Server数据库完整指南,整合了ADO.NET原生连接与Entity Framework Core两种实现方式。
这篇文件详细介绍C#代码连接
数据库的通用操作
数据库链接功能 数据库的增删改查操作
1 配置全局数据库链接字符串 App.config
2 获取数据库链接字符串
先在App.config配置连接字符串
//name 自定义名称 服务器名称Server=ip地址 端口号;数据库名称 账号-密码
server=.
:指定服务器名称为 .(自己计算机)
,表示数据库服务器位于本地计算机上。.用于指代本地主机。
database=SMDB
:指定要连接的数据库名称为 SMDB
。这意味着连接成功后,将在 SMDB
数据库上执行数据库操作。
uid=sa
:指定用户身份验证使用的用户名为 sa
。sa
是 SQL Server 中的系统管理员账户。
pwd=123456
:指定用户身份验证使用的密码为 123456
。
//获取
public static readonly string connstring = ConfigurationManager.ConnectionStrings[\"c1\"].ToString();
注:也可以在c#创建字符串来设置连接字符串在进行获取
* 执行sql命令几个方法
* 1 cmd.ExCuteNonQuery 添加数据(insert into) 修改数据update 删除数据delete
* 2 cmd.ExcuteScalar select count(*)
* 3 cmd.ExcuteReader 返回的是sqlDatareader 管道 需要使用while循环, select *
* 4 SqlDataAdapter da = new DataAdapter(cmd) ,select * 场景
展示案例
获取单一结果的方法 列如 记录个数等功能
//获取单一结果的方法 列如 记录个数等功能public static object GrSigleResult(string sql){ //1创建数据库连接 SqlConnection=new SqlConnection(connstring); //2创建sql命令 SqlCommand cmd=new SqlCommand(sql,conn) //打开连接执行命令 try { conn.open(); return cmd.ExecuteScalar(); } catch(Exception){throw;} finally{conn.Close();}}方法调用: // 获取总人数 public static int GetStudentCount() { string sql = \"select count(*) from Students\"; return Convert.ToInt32(SQLHelper.GrtSigleResult(sql)); }
执行增删改查操作
//执行增删改查操作public static int Update(string sql){ SqlConnection conn=new SqlConnection(connstring); SqlCommand cmd=new SqlCommand(sql,conn); try { conn.open(); return cmd.ExecuteNonQuery(); } catch(Exception){throw;} finally{conn.Close();}}方法调用:public static bool ClockInSuccess(Attendance ad){ string sql = \"insert into Attendance(CarNo) Values(\'{0}\')\"; sql = string.Format(sql,ad.CardNo); try { SQLHelper.Update(sql); return true; } catch (Exception) { throw; }}
SqlDataReader 存储数据库数据 获取数据的所有记录 要用while循环去读
public static SqlDataReader GetReader(string sql) { SqlConnection conn = new SqlConnection(connstring); SqlCommand cmd = new SqlCommand(sql,conn); try { conn.Open(); return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection); } catch (Exception) { throw; } }方法调用: 1 返回的是对象类型 public static Student GetStudentByCardNo(string cardNo) { string sql = \"select StudentId,StudentName,Gender,Birthday,StudentIdNo,PhoneNumber,ClassName,StudentAddress,CardNo,StuImage from Students \"; sql += \"inner join StudentClass on Students.ClassId = StudentClass.ClassId \"; sql += \"where CardNo = \'{0}\'\"; sql = string.Format(sql, cardNo); SqlDataReader r = SQLHelper.GetReader(sql); Student student = null; if (r.Read()) { student = new Student() { StudentId = Convert.ToInt32(r[\"StudentId\"]), StudentName = r[\"StudentName\"].ToString(), Gender = r[\"Gender\"].ToString(), BirthDay = Convert.ToDateTime(r[\"Birthday\"]), StudentIdNo = r[\"StudentIdNo\"].ToString(), PhoneNumber = r[\"PhoneNumber\"].ToString(), ClassName = r[\"ClassName\"].ToString(), StudentAddress = r[\"StudentAddress\"].ToString(), CarNo = r[\"CardNo\"].ToString(), StuImage = r[\"StuImage\"] == null ? \"\" : r[\"StuImage\"].ToString(), }; } r.Close(); return student; }2返回list集合 public static List GetScoreList(string cname) { //全校成绩 string sql = \"select Students.StudentId, StudentName,ClassName,Gender,CSharp,SqlserverDB from Students inner join ScoreList on Students.StudentId=ScoreList.StudentId inner join StudentClass on StudentClass.ClassId = Students.ClassId \"; if (cname != null && cname.Length != 0) { //按照班级查询 sql += \"where ClassName = \'\" + cname + \"\'\"; } SqlDataReader r = SQLHelper.GetReader(sql); List list = new List(); while (r.Read()) { list.Add(new Student() { StudentId = Convert.ToInt32(r[\"StudentId\"]), StudentName = r[\"StudentName\"].ToString(), Gender = r[\"Gender\"].ToString(), ClassName = r[\"ClassName\"].ToString(), CSharp = Convert.ToInt32(r[\"CSharp\"]), SqlserverDB = Convert.ToInt32(r[\"SqlserverDB\"]), }); } r.Close(); return list; }
获取所有的记录 返回的是dataset数据类型 不要逐条给实体类字段进行赋值
public static DataSet GetDateSet(string sql){ SqlConnection conn = new SqlConnection(connstring); SqlCommand cmd = new SqlCommand(sql,conn); DataSet ds=new DataSet(); SqlDataAdapter da=new SqlDataAdapter(cmd) try { conn.Open(); da.Fill(ds); // 把数据表数据填充在dataset集合中 return ds; } catch (Exception) { throw; } finally { conn.Close() ; } }方法调用: /// /// 获取所有成绩的方法 /// /// public static DataSet GetAllScore() { string sql = \"select Students.StudentId,StudentName,ClassName,Gender,PhoneNumber,CSharp,SqlserverDB from ScoreList inner join Students on Students.StudentId = ScoreList.StudentId inner join StudentClass on StudentClass.ClassId = Students.ClassId\"; return SQLHelper.GetDateSet(sql); }Ui: private DataSet ds = null; // 放置所有的成绩 数据集 this.ds = ScoreService.GetAllScore();
获取服务器时间
public static DateTime GetDateTime() { return Convert.ToDateTime(GrtSigleResult(\"select getdate()\")); }方法调用: DateTime t0 = Convert.ToDateTime(SQLHelper.GetDateTime().ToShortDateString()); public static bool UpdateDBFormExcelByShiWu(List list) { SqlConnection conn = new SqlConnection(connstring); SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; try { conn.Open(); // 开启事物 cmd.Transaction = conn.BeginTransaction(); // 把list里面指令添加事务中 foreach (string s in list) { cmd.CommandText = s; cmd.ExecuteNonQuery(); } cmd.Transaction.Commit(); return true; } catch (Exception ex) { MessageBox.Show(\"添加失败,\" + ex); return false; } finally { conn.Close(); } }方法调用: public static bool SaveDataToDB(List list) { // 定义sql语句 StringBuilder sql = new StringBuilder(\"insert into Students \"); sql.Append(\"(StudentName,Gender,BirthDay,StudentIdNo,CardNo,Age,PhoneNumber,StudentAddress,ClassId) \"); sql.Append(\"values \"); sql.Append(\"(\'{0}\',\'{1}\',\'{2}\',\'{3}\',\'{4}\',\'{5}\',\'{6}\',\'{7}\',\'{8}\');\"); // 2 创建一个保存sql语句的集合 List sqlList = new List(); // 3 遍历传递过来的学生集合对象 int i = 1213; foreach (Student student in list) { string s = string.Format(sql.ToString(), student.StudentName, student.Gender, student.BirthDay.ToString(\"yyyy-MM-dd\"), student.StudentIdNo, student.CarNo+i, student.Age, student.PhoneNumber, student.StudentAddress, student.ClassId); sqlList.Add(s); i++; } return SQLHelper.UpdateDBFormExcelByShiWu(sqlList); }
SQL注入
当我们要在登录账号密码时 不知道账号密码 可以字符串拼接 直接登录 或一些其他删除表等操作
比如用户输入: \' or 1=1 -- 就可以成功登录了\'是跟前面输入的sql语句连接 or 1=1 当条件成立时 然后就可以成功登录 --是省略后面的 甚至可以执行删库的操作: \'; drop database xxxx
防止sql注入的方法就是避免直接将用户输入的内容拼接到sql语句中
使用带参数的sql语句执行数据库操作就可以避免sql注入
使用带参数的sql语句不需要关注sql语句带引号的问题
在sql语句中 使用@xxx 定义sql参数
案列:
// 2、在SqlCommand对象中为sql参数赋值 // 添加参数的方法1(推荐) // cmd.Parameters.AddWithValue(\"@abc\", textBox1.Text); // 添加一个参数,并为参数赋值 // cmd.Parameters.AddWithValue(\"@efg\", textBox2.Text); // 添加参数的方法2 //cmd.Parameters.Add(\"@abc\", SqlDbType.VarChar); // 添加一个参数,并指定参数的类型 //cmd.Parameters[\"@abc\"].Value = textBox1.Text; // 为@abc参数赋值 //cmd.Parameters.Add(\"@efg\", SqlDbType.VarChar); //cmd.Parameters[\"@efg\"].Value = textBox2.Text; // 添加参数的方法3 //cmd.Parameters.Add(new SqlParameter(\"@abc\", textBox1.Text)); //cmd.Parameters.Add(new SqlParameter(\"@efg\", textBox2.Text)); // 添加参数的方法4(推荐) SqlParameter[] parameters = new SqlParameter[] { new SqlParameter(\"@abc\", textBox1.Text), new SqlParameter(\"@efg\", textBox2.Text) }; cmd.Parameters.AddRange(parameters); 封装几个类的方法 /// /// 执行增删改操作 /// /// 要执行的sql语句 /// 传递的sql参数 /// public static int Update(string sql, params SqlParameter[] parameter) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(parameter); return cmd.ExecuteNonQuery(); } /// /// 执行查询操作 /// /// 要执行的sql语句 /// 传递的sql参数 /// public static SqlDataReader GetData(string sql, params SqlParameter[] parameter) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(parameter); return cmd.ExecuteReader(); } /// /// 执行单行单列的查询操作 /// /// 要执行的sql语句 /// 传递的sql参数 /// public static object GetObject(string sql, params SqlParameter[] parameter) { SqlCommand cmd = new SqlCommand(sql, conn); cmd.Parameters.AddRange(parameter); return cmd.ExecuteScalar(); }
下一节讲EF(Entity Framework) 不需要写连接字符串 因为在写字符串也很难查找报错地方因为字符串写错问题 以及连接创建许多代码 和查询等还需要注意SQL防注入