C# ADO.NET 调用存储过程 和 SqlDataReader
调用SQL Server存储过程,使用SqlDataReader流式读取查询结果,核心要点:
SqlCommand.CommandType = CommandType.StoredProcedure标记执行存储过程- 使用
SqlParameter传递存储过程参数 ExecuteReader(CommandBehavior.CloseConnection)读取数据流- SqlDataReader是向前只读、流式读取器,用完必须关闭
存储过程定义
读者需要到数据库中事先创建好存储过程,然后才可以调用。
create proc myProc
@id int
as
select * from [dbo].[Article] where id>@id
go
-- 调用测试
exec myProc @id=5Code language: JavaScript (javascript)
接收参数@id,查询Article表中id大于传入值的数据。
C#中调用存储过程
使用ExecuteReader返回SqlDataReader ,可以获取多条数据。
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = conn;
sqlCom.CommandText = "myProc";
sqlCom.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("@id", SqlDbType.Int, 8);
param.Value = 4;
param.Direction = ParameterDirection.Input;
sqlCom.Parameters.Add(param);
SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection);
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
sb.AppendLine(reader[0] + "-" + reader[1]);
}
reader.Close();
MessageBox.Show(sb.ToString());
}Code language: C# (cs)
using释放Reader,避免资源泄漏
string connectionString = "Data Source=.;Initial Catalog=db;Integrated Security=SSPI;";
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand sqlCom = new SqlCommand("myProc", conn))
{
sqlCom.CommandType = CommandType.StoredProcedure;//表明命令是存储过程
// 添加输入参数
sqlCom.Parameters.Add("@id", SqlDbType.Int).Value = 4;
// CommandBehavior.CloseConnection:reader关闭时自动关闭连接
using (SqlDataReader reader = sqlCom.ExecuteReader(CommandBehavior.CloseConnection))
{
StringBuilder sb = new StringBuilder();
while (reader.Read())
{
// reader[0]第1列,reader[1]第2列;也可以写reader["列名"]
sb.AppendLine($"{reader[0]}-{reader[1]}");
}
MessageBox.Show(sb.ToString());
}
// 不需要手动reader.Close(),using会自动释放
}
}Code language: C# (cs)
CommandType 三种枚举
CommandType.Text:执行普通SQL语句CommandType.StoredProcedure:执行存储过程CommandType.TableDirect:直接读取数据表
不设置
StoredProcedure,程序会把存储过程名当成普通SQL执行,直接报错!
SqlParameter 参数方向
ParameterDirection.Input:输入参数(传入值,最常用)ParameterDirection.Output:输出参数ParameterDirection.InputOutput:输入输出双向ParameterDirection.ReturnValue:存储过程返回值
CommandBehavior.CloseConnection 作用
当SqlDataReader调用Close()/释放时,自动关闭关联的SqlConnection。
适合场景:方法返回Reader对象,外部读完数据后自动回收连接。
SqlDataReader 重要特性
- 只进只读:只能
Read()向下遍历,不能回头、不能修改数据 - 连接占用:Reader打开期间,数据库连接不能执行其他操作
- 资源必须释放:要么手动
reader.Close(),优先使用using自动释放 - 读取列两种方式:
csharp reader[0]; // 通过索引读取 reader["Title"]; // 通过字段名读取(可读性更强)
注意
- 忘记设置
CommandType.StoredProcedure→ 执行异常 - 参数名称大小写、拼写和存储过程不一致 → 参数不匹配
- Reader没有关闭 → 数据库连接持续占用,造成连接池耗尽
- 在
while(reader.Read())内部执行新数据库查询:同一个连接不能同时多个Reader - 存储过程参数缺失、参数类型不匹配 → 执行报错
对比
| 执行方式 | 适用场景 | 返回对象 |
|---|---|---|
| ExecuteNonQuery | 增删改存储过程 | 受影响行数 int |
| ExecuteScalar | 返回单行单列(聚合查询) | object |
| ExecuteReader | 返回多行数据集 | SqlDataReader(流式读取) |
Previous: SqlTransaction 数据库事务
Next: SqlDataAdapter