SQL Server数据库
查询
SqlConnection实例化建立连接
.Open打开连接
打包sql查询语句
例子: string sql = "SELECT Id, DeviceName, Temperature, RecordTime FROM DeviceTemp ORDER BY Id";
实例化SqlCommand并传入连接实例和打包的sql语句
为什么用它打包参数?
可以添加查询参数,实现参数化查询,防止 SQL 注入
cmd.Parameters.Add("@dir", SqlDbType.NVarChar,10).Value = "接收";
SqlDataAdapter可以直接传入sql,但只能执行不带参数的简单 SQL
实例化SqlDataAdapter并传入SqlCommand实例
实例DataTable内存临时表
SqlDataAdapter实例调用Fill函数并传入DataTable实例
作用是把查询到的数据搬运到内存表里
表格直接对接它实例就可以显示内容
用using包裹住实例化代码,释放资源
SqlConnection、SqlCommand、SqlDataAdapter 全都实现了接口 IDisposable自动释放
哪些对象需要 using
非托管资源:数据库连接、网络通道、内存句柄
不释放会咋样?
数据库连接泄漏,连接不会归还池子,一直被标记为占用状态
短期没问题,时间长开始卡顿,报错
增加
判断框内是否有要增加的数据
实例化-打开连接
打包sql语句
SqlCommand实例化传入sql和连接
调用函数传入增加的数据
cmd.Parameters.AddWithValue("@devisename", txtDeviceName.Text);
调用函数查询受影响行数
用于判断是否增加成功
int rows = cmd.ExecuteNonQuery();
if (rows > 0)增加成功
修改
判断是否选中要修改的行
if(dgvData.SelectedRows.Count==0)
获取选中行Id,主键
选中主键,唯一标识一行,改谁就靠它
int id = Convert.ToInt32(dgvData.SelectedRows[0].Cells["Id"].Value);
判断框内是否填入要修改的值
实例打开连接
加作用域限定
规定只改Id选中的那一行
★必须有 WHERE,没有 WHERE 会把整张表全改了
string sql = "UPDATE DeviceTemp SET DeviceName=@name, Temperature=@temp WHERE Id=@id";
调用函数传入修改的数据
cmd.Parameters.AddWithValue("@name", txtDeviceName.Text);
删除
判断是否选中删除行
获取选中行Id
选中主键,唯一标识一行,删谁就靠它
二次确认删除防误删
DialogResult result = MessageBox.Show("确定要删除这条记录吗?", "确认删除",//二次确认防止手滑误删 MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result != DialogResult.Yes) return;
实例化-建立连接
打包sql
加WHERE 作用域限定
调用函数传入要删除的主键
除了查询几乎都是统一流程
增删改
Connection → Open→sql →Commandcmd→ cmd.Parameters.AddWithValue
查
Connection → Open→sql→ Commandcmd→SqlDataAdapter →DataTable→adapter.Fill(dt)
都可以用这个函数判断是否执行成功
int rows = cmd.ExecuteNonQuery()
获取受影响行数
最上方连接字符串
string connStr = @"Data Source=localhost; Database = SerialDB; Integrated Security = True; TrustServerCertificate = True;";
localhost本地实例名
Database=FactoryDB → 要连的数据库名
Integrated Security=True → Windows身份验证(不用输密码)
TrustServerCertificate=True → 信任本地证书,避免报错
SqlCommand 完整能干的所有事情
承载 SQL 文本、存放参数-防注入
cmd.Parameters.Add("@key",SqlDbType.NVarChar).Value=searchText;
设置命令类型:普通 SQL / 存储过程
cmd.CommandType = CommandType.StoredProcedure;
设置命令超时时间(查询很慢防止卡死)
cmd.CommandTimeout = 30;
执行增删改 ExecuteNonQuery、单行查询 ExecuteScalar、数据流读取 ExecuteReader
配合数据库事务
cmd.Transaction = sqlTrans;
读取
SqlDataReader
一边从数据库拿数据,一边逐行读取,不把整张表一次性加载到内存
数据量大、只看一遍 省内存,但不能回头
不是new出来的
SqlDataReader reader = cmd.ExecuteReader
SqlDataAdapter批量把数据搬进内存
DataTable / DataSet内存里的表,搬来的数据放这里
参数化查询(防 SQL 注入)
什么是 SQL 注入?
用户输入被数据库当成「SQL 语法」来解析
用户在输入框里写 '; DROP TABLE DeviceTemp; --,如果直接拼字符串,整张表就被删了
解决:
参数化查询
第一步:只把 SQL 模板发给数据库,先编译
第二步:单独传输参数值
必须使用 Command.Parameters 添加参数才是真参数化
封装数据访问层(SqlHelper)
为什么要封装?
不封装的话,每次查数据都要写一坨:开连接 → 写 SQL → 执行 → 关连接。重复代码堆积,改一个连接字符串要改 50 个地方。
存储过程
什么是存储过程?
SQL 语句写在数据库里,起个名字,C# 按名字调用。相当于数据库里的"函数"
为什么用?
预编译,性能快一点
C# 看不到 SQL,更安全
和正常的C#写sql比要改哪些?
sql直接打包存储过程的名
string sql = "usp_UpdateDevice";
后面需要加cmd.CommandType = CommandType.StoredProcedure;
否则C#会认为sql里打包的是字符串
★重点:
在使用cmd点调用增删改值时,@的参数名必须和sql语句里写的一样,否则报错
作成者