ADO.NET在 .NET 平台的后端开发中数据库交互是核心能力之一而 ADO.NET 作为微软官方提供的标准化数据访问技术栈是操作关系型数据库的基石。本文将以 SQL Server 为例系统梳理 ADO.NET 的五大核心对象、两种访问模式、事务处理与工具类封装带你从零掌握连接式与断开式两套数据访问方案。一、ADO.NET 概述1.1 什么是 ADO.NETADO.NET 是 .NET Framework /.NET Core 中负责数据访问的类库集合是应用程序与数据源之间的桥梁。它原生支持 SQL Server同时可兼容 MySQL、Oracle 等多种关系型数据库提供了完全面向对象的数据访问架构可实现数据的查询、新增、修改、删除等全量操作。1.2 核心优势ADO.NET 最突出的设计是断开式数据访问架构应用程序可以在与数据库断开连接的情况下在内存中完成数据的读取、修改最后再批量将变更同步回数据库。这种设计大幅减少了数据库连接的占用时长降低了服务器资源消耗尤其适合多层架构与高并发业务场景。1.3 两大访问模式连接式访问全程保持数据库连接通过CommandDataReader逐行读取数据适合大数据量、只读向前的高性能查询场景。断开式访问通过DataAdapter将数据一次性填充到内存DataSet中之后关闭连接在内存中操作数据最后统一回写数据库。二、环境准备与命名空间操作 SQL Server 无需额外下载第三方驱动.NET 框架内置了对应类库只需引入核心命名空间即可csharp运行using System.Data; // 数据通用基类DataSet、DataTable 等 using System.Data.SqlClient; // SQL Server 专属数据提供程序补充说明System.Data.SqlClient是 .NET Framework 时代的标准库若使用 .NET Core /.NET 5 平台推荐使用Microsoft.Data.SqlClient核心 API 完全向下兼容。三、ADO.NET 五大核心对象3.1 SqlConnection数据库连接对象SqlConnection负责建立应用程序与数据库之间的物理连接是所有数据操作的入口。1连接字符串SQL Server 两种常用连接字符串格式Windows 身份验证Data Source服务器地址;Initial Catalog数据库名;Integrated SecurityTrueSQL Server 身份验证Data Source服务器地址;Initial Catalog数据库名;User ID用户名;Password密码示例csharp运行string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue;2核心属性与方法表格属性说明ConnectionString获取或设置数据库连接字符串State获取当前连接状态ConnectionState枚举类型表格方法说明Open()打开数据库连接Close()关闭数据库连接ConnectionState常用枚举值Open连接已打开Closed连接已关闭Connecting正在连接中Broken连接中断可关闭后重新打开3标准连接示例数据库连接属于稀缺资源必须保证使用后释放推荐配合try-catch-finally或using语句csharp运行using System;进行知识总结完成一篇 CSDN 博客创作已完成思考ADO.NET 完全指南SQL Server 数据访问核心对象与实战封装C#本文系统梳理 ADO.NET 访问 SQL Server 的完整知识体系涵盖五大核心对象、连接式与断开式两种访问模式、事务处理及生产级 DBHelper 封装附完整可运行代码适合 .NET 开发者入门与复习查阅。一、前言在 .NET 生态中ADO.NET 是微软官方提供的底层数据访问技术栈是操作关系型数据库的基石。无论是 EF Core 等 ORM 框架还是各类数据库操作组件底层大多基于 ADO.NET 实现。掌握原生 ADO.NET能帮助我们深刻理解数据库交互原理排查底层性能与连接问题。本文以SQL Server为数据源从基础概念到核心对象从事务处理到工具类封装完整讲解 ADO.NET 的实战用法。二、ADO.NET 核心概述2.1 什么是 ADO.NETADO.NET 是 .NET Framework /.NET Core 中负责数据访问的类库集合是应用程序与数据源之间的标准化桥梁。它原生深度支持 SQL Server同时兼容 MySQL、Oracle 等主流关系型数据库提供完全面向对象的数据访问架构可实现数据的增、删、改、查全量操作。其最核心的设计优势是断开式数据访问架构应用程序可在与数据库断开连接的状态下在内存中完成数据读取与修改最后批量将变更同步回数据库大幅减少数据库连接占用时长降低服务器资源消耗。2.2 两大数据访问模式表格访问模式核心组件特点适用场景连接式访问SqlCommandSqlDataReader全程保持连接只读向前逐行读取内存占用低、读取速度快大数据量只读查询、列表遍历断开式访问SqlDataAdapterDataSet/DataTable一次性加载数据到内存断开连接后仍可操作最后统一回写离线数据编辑、小批量数据处理、多层架构数据传输三、环境准备与命名空间操作 SQL Server 无需额外下载第三方驱动.NET 框架内置原生支持。.NET Framework使用System.Data.SqlClient命名空间.NET Core / .NET 5推荐使用 NuGet 包Microsoft.Data.SqlClientAPI 完全向下兼容核心引入csharp运行using System.Data; // 通用数据类DataSet、DataTable、枚举等 using System.Data.SqlClient; // SQL Server 原生数据提供程序四、五大核心对象详解与实战4.1 SqlConnection数据库连接对象SqlConnection负责建立应用程序与 SQL Server 之间的物理连接是所有数据操作的入口。核心属性与方法表格属性说明ConnectionString数据库连接字符串State当前连接状态ConnectionState枚举类型表格方法说明Open()打开数据库连接Close()关闭数据库连接Dispose()释放连接资源ConnectionState常用枚举Open已打开、Closed已关闭、Connecting连接中、Broken连接中断。连接字符串SQL Server 两种常用认证方式csharp运行// Windows 身份验证本地开发推荐 string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue; // SQL Server 身份验证 string connStr Data Source127.0.0.1;Initial CatalogTestDB;User IDsa;Password123456;标准连接示例数据库连接是稀缺资源必须保证使用后释放推荐使用using语句自动释放csharp运行string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue; // using 语句执行结束后自动释放连接无需手动 Close using (SqlConnection conn new SqlConnection(connStr)) { try { conn.Open(); Console.WriteLine($数据库连接成功当前状态{conn.State}); } catch (Exception ex) { Console.WriteLine($连接失败{ex.Message}); } }4.2 SqlCommandSQL 命令执行对象SqlCommand用于执行具体的 SQL 语句或存储过程实现增删改查操作执行过程中必须保持数据库连接。核心属性与方法表格属性说明CommandText要执行的 SQL 语句 / 存储过程名Connection关联的数据库连接对象ParametersSQL 参数集合用于参数化查询表格方法说明适用场景ExecuteNonQuery()返回受影响行数int增、删、改操作ExecuteScalar()返回结果集首行首列object聚合查询count、sum、单值查询ExecuteReader()返回SqlDataReader对象多行多列查询实战 1执行增删改ExecuteNonQuerycsharp运行string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue; string sql INSERT INTO Users(UserName, Password) VALUES(UserName, Password); using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); using (SqlCommand cmd new SqlCommand(sql, conn)) { // 参数化查询防止 SQL 注入开发必须规范 cmd.Parameters.AddWithValue(UserName, zhangsan); cmd.Parameters.AddWithValue(Password, 123456); int rows cmd.ExecuteNonQuery(); Console.WriteLine(rows 0 ? 新增成功 : 新增失败); } }✅ 重要规范禁止字符串拼接 SQL必须使用参数化查询杜绝 SQL 注入风险。实战 2单值查询ExecuteScalarcsharp运行string sql SELECT COUNT(*) FROM Users; using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); SqlCommand cmd new SqlCommand(sql, conn); int count Convert.ToInt32(cmd.ExecuteScalar()); Console.WriteLine($用户总数{count}); }4.3 SqlDataReader只读向前数据读取器SqlDataReader是连接式查询的核心以只读、向前的方式逐行读取数据内存占用极低读取性能优异。核心属性与方法表格属性说明HasRows是否包含数据boolFieldCount当前行的列数表格方法说明Read()前进到下一行有数据返回 true无数据返回 falseClose()关闭读取器GetInt32() / GetString()按列索引获取指定类型的值完整查询示例csharp运行string sql SELECT Id, UserName, Password FROM Users; using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); SqlCommand cmd new SqlCommand(sql, conn); using (SqlDataReader dr cmd.ExecuteReader()) { Console.WriteLine(编号\t用户名\t密码); while (dr.Read()) // 逐行读取 { // 两种取值方式列名索引 / 列序号索引 int id dr.GetInt32(0); string userName dr[UserName].ToString(); string password dr[Password].ToString(); Console.WriteLine(${id}\t{userName}\t{password}); } } }⚠️ 注意SqlDataReader读取期间必须保持数据库连接打开使用完毕必须及时关闭否则会占用连接资源。4.4 DataSet DataTable内存数据集合DataSet可以理解为内存中的数据库是一个独立于数据源的数据容器断开数据库连接后依然可用。内部以 XML 格式存储数据可包含多张DataTable并支持表关系、数据约束、行状态管理。DataSet数据表的集合包含多个DataTableDataTable内存中的一张数据表由DataRow行和DataColumn列组成内存构建 DataTable 示例csharp运行// 创建数据集 DataSet ds new DataSet(MyDataSet); // 创建数据表并加入数据集 DataTable dt new DataTable(UserInfo); ds.Tables.Add(dt); // 添加列结构 dt.Columns.Add(Id, typeof(int)); dt.Columns.Add(Name, typeof(string)); dt.Columns.Add(Age, typeof(int)); // 添加数据行 dt.Rows.Add(1, 张三, 25); dt.Rows.Add(2, 李四, 30); // 条件过滤 DataRow[] rows dt.Select(Age 25); // 修改数据 dt.Rows[0][Name] 张三_更新; // 删除行 dt.Rows[1].Delete(); // 遍历数据 foreach (DataRow row in dt.Rows) { Console.WriteLine(${row[Id]}\t{row[Name]}\t{row[Age]}); }4.5 SqlDataAdapter数据适配器断开式核心SqlDataAdapter是连接数据库与DataSet的桥梁负责从数据库拉取数据填充到内存DataSet也负责将内存中的变更批量回写到数据库。核心方法Fill(DataSet ds)执行查询将数据填充到 DataSetUpdate(DataSet ds)将 DataSet 中的变更批量更新回数据库填充 DataTable 示例csharp运行string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue; string sql SELECT Id, UserName, Password FROM Users; // DataAdapter 会自动管理连接无需手动 Open/Close SqlDataAdapter sda new SqlDataAdapter(sql, connStr); DataTable dt new DataTable(); sda.Fill(dt); // 自动打开连接、填充数据、关闭连接 // 离线状态下直接遍历数据 foreach (DataRow row in dt.Rows) { Console.WriteLine(${row[Id]}\t{row[UserName]}\t{row[Password]}); }五、SQL Server 事务处理事务用于保证一组 SQL 操作要么全部成功、要么全部失败典型场景如转账、订单生成。ADO.NET 通过SqlTransaction实现事务控制。事务核心步骤打开连接后开启事务conn.BeginTransaction()将事务对象绑定到 SqlCommandcmd.Transaction transaction全部执行成功transaction.Commit()提交出现异常transaction.Rollback()回滚完整转账示例csharp运行string connStr Data Source.;Initial CatalogTestDB;Integrated SecurityTrue; using (SqlConnection conn new SqlConnection(connStr)) { conn.Open(); // 开启事务可指定隔离级别 SqlTransaction tran conn.BeginTransaction(IsolationLevel.Serializable); try { // 操作1张三账户扣减500 SqlCommand cmd1 new SqlCommand( UPDATE Account SET Balance Balance - 500 WHERE Name张三, conn, tran); cmd1.ExecuteNonQuery(); // 操作2李四账户增加500 SqlCommand cmd2 new SqlCommand( UPDATE Account SET Balance Balance 500 WHERE Name李四, conn, tran); cmd2.ExecuteNonQuery(); // 全部成功提交事务 tran.Commit(); Console.WriteLine(转账成功); } catch (Exception ex) { // 出现异常回滚所有操作 tran.Rollback(); Console.WriteLine($转账失败已回滚{ex.Message}); } }六、通用 DBHelper 工具类封装生产级原生 ADO.NET 代码重复度高实际开发中通常封装为DBHelper工具类统一管理连接、异常处理与资源释放。封装后的 DBHelper 类csharp运行/// summary /// SQL Server 数据库操作帮助类 /// /summary public class DBHelper { private readonly string _connectionString; /// summary /// 构造函数传入连接字符串 /// /summary public DBHelper(string connectionString) { _connectionString connectionString; } /// summary /// 执行增删改返回受影响行数 /// /summary public int ExecuteNonQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(_connectionString)) using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null parameters.Length 0) cmd.Parameters.AddRange(parameters); conn.Open(); return cmd.ExecuteNonQuery(); } } /// summary /// 执行查询返回首行首列 /// /summary public object ExecuteScalar(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(_connectionString)) using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null parameters.Length 0) cmd.Parameters.AddRange(parameters); conn.Open(); return cmd.ExecuteScalar(); } } /// summary /// 执行查询返回 DataTable离线 /// /summary public DataTable ExecuteQuery(string sql, params SqlParameter[] parameters) { using (SqlConnection conn new SqlConnection(_connectionString)) using (SqlCommand cmd new SqlCommand(sql, conn)) { if (parameters ! null parameters.Length 0) cmd.Parameters.AddRange(parameters); SqlDataAdapter sda new SqlDataAdapter(cmd); DataTable dt new DataTable(); sda.Fill(dt); return dt; } } }调用示例csharp运行// 初始化帮助类 DBHelper db new DBHelper(Data Source.;Initial CatalogTestDB;Integrated SecurityTrue); // 登录验证参数化查询 string sql SELECT COUNT(*) FROM Users WHERE UserNameUserName AND PasswordPassword; SqlParameter[] paras { new SqlParameter(UserName, zhangsan), new SqlParameter(Password, 123456) }; int count Convert.ToInt32(db.ExecuteScalar(sql, paras)); Console.WriteLine(count 0 ? 登录成功 : 用户名或密码错误);七、两种访问模式对比与选型表格维度连接式DataReader断开式DataSet/DataTable连接占用全程保持连接填充后即释放连接内存占用低逐行读取高全量加载到内存读取速度快相对较慢数据编辑只读不可修改支持离线增删改适用场景大数据量列表查询、只读遍历小批量数据编辑、多层架构数据传递、数据绑定八、最佳实践与常见避坑必须使用参数化查询禁止字符串拼接 SQL防止 SQL 注入及时释放连接优先使用using语句自动释放连接、命令、读取器资源避免长时间占用连接数据读取完成后立即关闭连接不要持有长连接异常处理数据库操作必须包裹异常捕获保证异常时连接能正常关闭大数据量查询优先使用SqlDataReader而非DataTable避免内存溢出事务范围事务内只包含必要的数据库操作避免长事务引发锁问题九、总结ADO.NET 是 .NET 数据库开发的底层根基SqlConnection负责建立连接SqlCommand负责执行命令SqlDataReader实现连接式高速读取DataSetSqlDataAdapter构建断开式离线数据模型SqlTransaction保证数据一致性。掌握原生 ADO.NET 后再学习 EF Core、Dapper 等 ORM 框架会更加轻松也能更精准地定位和解决数据访问层的性能问题。