跳转到内容

C Sharp 数据读取器

来自代码酷

C#数据读取器[编辑 | 编辑源代码]

C#数据读取器(DataReader)是.NET框架中用于高效读取数据库数据的核心组件,属于`System.Data`命名空间下的轻量级只进流式读取器。它专为高性能数据访问设计,适用于需要快速遍历大量数据的场景。

核心特性[编辑 | 编辑源代码]

  • 只进只读:单向遍历结果集,不支持修改数据或反向移动
  • 连接依赖:需保持数据库连接打开状态
  • 低内存消耗:不缓存整个结果集,逐行处理
  • 高性能:比DataSet/DataTable更高效处理大数据量

基础实现[编辑 | 编辑源代码]

主要使用`IDataReader`接口及其实现类(如`SqlDataReader`、`OleDbDataReader`等):

using System.Data.SqlClient;

// 基本使用模式
string connectionString = "Server=.;Database=Northwind;Integrated Security=True;";
using (SqlConnection connection = new SqlConnection(connectionString))
{
    SqlCommand command = new SqlCommand("SELECT ProductID, ProductName FROM Products", connection);
    connection.Open();
    
    using (SqlDataReader reader = command.ExecuteReader())
    {
        while (reader.Read()) // 逐行前进
        {
            int id = reader.GetInt32(0);        // 按索引获取
            string name = reader.GetString(1);   // 或 reader["ProductName"].ToString()
            Console.WriteLine($"{id}: {name}");
        }
    }
}

输出示例[编辑 | 编辑源代码]

1: Chai
2: Chang
3: Aniseed Syrup
...

关键技术点[编辑 | 编辑源代码]

数据类型处理[编辑 | 编辑源代码]

数据读取器提供类型安全的方法:

常用Get方法
方法 描述
GetInt32() 读取32位整数
GetString() 读取字符串值
GetDateTime() 读取日期时间
GetOrdinal() 获取列索引

多结果集处理[编辑 | 编辑源代码]

当执行返回多个结果集的命令时:

using (SqlDataReader reader = command.ExecuteReader())
{
    do // 处理每个结果集
    {
        while (reader.Read())
        {
            // 处理当前结果集行
        }
    } 
    while (reader.NextResult()); // 移动到下一个结果集
}

性能优化[编辑 | 编辑源代码]

graph TD A[开始查询] --> B{使用DataReader?} B -->|是| C[保持连接打开] C --> D[使用GetXXX方法] D --> E[及时关闭读取器] B -->|否| F[考虑其他方案]

优化建议:

  • 始终使用`using`语句确保资源释放
  • 优先使用列索引而非列名(`reader.GetInt32(0)`比`reader["ProductID"]`更快)
  • 处理NULL值:
string name = reader.IsDBNull(1) ? null : reader.GetString(1);

高级应用[编辑 | 编辑源代码]

映射到对象[编辑 | 编辑源代码]

public List<Product> GetProducts()
{
    var products = new List<Product>();
    // ...连接代码...
    while (reader.Read())
    {
        products.Add(new Product
        {
            Id = reader.GetInt32(0),
            Name = reader.GetString(1),
            Price = reader.GetDecimal(2)
        });
    }
    return products;
}

批量数据处理[编辑 | 编辑源代码]

处理大型数据集时可采用分页读取:

分页大小=总内存单行内存占用×安全系数

实际案例[编辑 | 编辑源代码]

库存管理系统中的实时报表生成: 1. 连接生产数据库 2. 使用DataReader快速遍历百万级库存记录 3. 实时计算库存周转率:

while (reader.Read())
{
    var turnover = reader.GetDouble(3) / reader.GetDouble(4);
    if (turnover < 0.5) 
        AlertSlowMoving(reader.GetString(0));
}

限制与替代方案[编辑 | 编辑源代码]

局限性

  • 不能直接绑定到数据控件(需转换为集合)
  • 需要手动管理连接

替代选择

  • DataAdapter/DataSet:需要断开式访问时
  • ORM框架(如Entity Framework):需要对象关系映射时

最佳实践总结[编辑 | 编辑源代码]

  1. 始终在`using`块中使用DataReader
  2. 优先使用类型特定的Get方法
  3. 及时处理NULL值
  4. 大数据量查询时考虑分页
  5. 复杂业务逻辑考虑结合DTO使用