news 2026/8/17 17:43:27

​ADO.NET 全面详解:SQL Server 数据访问从入门到实战​

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
​ADO.NET 全面详解:SQL Server 数据访问从入门到实战​

ADO.NET

在 .NET 平台的后端开发中,数据库交互是核心能力之一,而 ADO.NET 作为微软官方提供的标准化数据访问技术栈,是操作关系型数据库的基石。本文将以 SQL Server 为例,系统梳理 ADO.NET 的五大核心对象、两种访问模式、事务处理与工具类封装,带你从零掌握连接式与断开式两套数据访问方案。

一、ADO.NET 概述

1.1 什么是 ADO.NET

ADO.NET 是 .NET Framework /.NET Core 中负责数据访问的类库集合,是应用程序与数据源之间的桥梁。它原生支持 SQL Server,同时可兼容 MySQL、Oracle 等多种关系型数据库,提供了完全面向对象的数据访问架构,可实现数据的查询、新增、修改、删除等全量操作。

1.2 核心优势

ADO.NET 最突出的设计是断开式数据访问架构:应用程序可以在与数据库断开连接的情况下,在内存中完成数据的读取、修改,最后再批量将变更同步回数据库。这种设计大幅减少了数据库连接的占用时长,降低了服务器资源消耗,尤其适合多层架构与高并发业务场景。

1.3 两大访问模式

  • 连接式访问:全程保持数据库连接,通过Command+DataReader逐行读取数据,适合大数据量、只读向前的高性能查询场景。
  • 断开式访问:通过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 Security=True
  • SQL Server 身份验证:Data Source=服务器地址;Initial Catalog=数据库名;User ID=用户名;Password=密码

示例:

csharp

运行

string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True";
(2)核心属性与方法

表格

属性说明
ConnectionString获取或设置数据库连接字符串
State获取当前连接状态,ConnectionState枚举类型

表格

方法说明
Open()打开数据库连接
Close()关闭数据库连接

ConnectionState常用枚举值:

  • Open:连接已打开
  • Closed:连接已关闭
  • Connecting:正在连接中
  • Broken:连接中断,可关闭后重新打开
(3)标准连接示例

数据库连接属于稀缺资源,必须保证使用后释放,推荐配合try-catch-finallyusing语句:

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.NET

ADO.NET 是 .NET Framework /.NET Core 中负责数据访问的类库集合,是应用程序与数据源之间的标准化桥梁。它原生深度支持 SQL Server,同时兼容 MySQL、Oracle 等主流关系型数据库,提供完全面向对象的数据访问架构,可实现数据的增、删、改、查全量操作。

其最核心的设计优势是断开式数据访问架构:应用程序可在与数据库断开连接的状态下,在内存中完成数据读取与修改,最后批量将变更同步回数据库,大幅减少数据库连接占用时长,降低服务器资源消耗。

2.2 两大数据访问模式

表格

访问模式核心组件特点适用场景
连接式访问SqlCommand+SqlDataReader全程保持连接,只读向前逐行读取,内存占用低、读取速度快大数据量只读查询、列表遍历
断开式访问SqlDataAdapter+DataSet/DataTable一次性加载数据到内存,断开连接后仍可操作,最后统一回写离线数据编辑、小批量数据处理、多层架构数据传输

三、环境准备与命名空间

操作 SQL Server 无需额外下载第三方驱动,.NET 框架内置原生支持。

  • .NET Framework:使用System.Data.SqlClient命名空间
  • .NET Core / .NET 5+:推荐使用 NuGet 包Microsoft.Data.SqlClient,API 完全向下兼容

核心引入:

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 Catalog=TestDB;Integrated Security=True"; // SQL Server 身份验证 string connStr = "Data Source=127.0.0.1;Initial Catalog=TestDB;User ID=sa;Password=123456";
标准连接示例

数据库连接是稀缺资源,必须保证使用后释放,推荐使用using语句自动释放

csharp

运行

string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True"; // using 语句执行结束后自动释放连接,无需手动 Close using (SqlConnection conn = new SqlConnection(connStr)) { try { conn.Open(); Console.WriteLine($"数据库连接成功,当前状态:{conn.State}"); } catch (Exception ex) { Console.WriteLine($"连接失败:{ex.Message}"); } }

4.2 SqlCommand:SQL 命令执行对象

SqlCommand用于执行具体的 SQL 语句或存储过程,实现增删改查操作,执行过程中必须保持数据库连接。

核心属性与方法

表格

属性说明
CommandText要执行的 SQL 语句 / 存储过程名
Connection关联的数据库连接对象
ParametersSQL 参数集合(用于参数化查询)

表格

方法说明适用场景
ExecuteNonQuery()返回受影响行数(int)增、删、改操作
ExecuteScalar()返回结果集首行首列(object)聚合查询(count、sum)、单值查询
ExecuteReader()返回SqlDataReader对象多行多列查询
实战 1:执行增删改(ExecuteNonQuery)

csharp

运行

string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True"; 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:单值查询(ExecuteScalar)

csharp

运行

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是否包含数据(bool)
FieldCount当前行的列数

表格

方法说明
Read()前进到下一行,有数据返回 true,无数据返回 false
Close()关闭读取器
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:数据表的集合,包含多个DataTable
  • DataTable:内存中的一张数据表,由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):执行查询,将数据填充到 DataSet
  • Update(DataSet ds):将 DataSet 中的变更批量更新回数据库
填充 DataTable 示例

csharp

运行

string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True"; 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实现事务控制。

事务核心步骤

  1. 打开连接后开启事务:conn.BeginTransaction()
  2. 将事务对象绑定到 SqlCommand:cmd.Transaction = transaction
  3. 全部执行成功:transaction.Commit()提交
  4. 出现异常:transaction.Rollback()回滚

完整转账示例

csharp

运行

string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True"; 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 Catalog=TestDB;Integrated Security=True"); // 登录验证(参数化查询) string sql = "SELECT COUNT(*) FROM Users WHERE UserName=@UserName AND Password=@Password"; 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)
连接占用全程保持连接填充后即释放连接
内存占用低,逐行读取高,全量加载到内存
读取速度相对较慢
数据编辑只读,不可修改支持离线增删改
适用场景大数据量列表查询、只读遍历小批量数据编辑、多层架构数据传递、数据绑定

八、最佳实践与常见避坑

  1. 必须使用参数化查询:禁止字符串拼接 SQL,防止 SQL 注入
  2. 及时释放连接:优先使用using语句自动释放连接、命令、读取器资源
  3. 避免长时间占用连接:数据读取完成后立即关闭连接,不要持有长连接
  4. 异常处理:数据库操作必须包裹异常捕获,保证异常时连接能正常关闭
  5. 大数据量查询:优先使用SqlDataReader而非DataTable,避免内存溢出
  6. 事务范围:事务内只包含必要的数据库操作,避免长事务引发锁问题

九、总结

ADO.NET 是 .NET 数据库开发的底层根基:SqlConnection负责建立连接,SqlCommand负责执行命令,SqlDataReader实现连接式高速读取,DataSet+SqlDataAdapter构建断开式离线数据模型,SqlTransaction保证数据一致性。

掌握原生 ADO.NET 后,再学习 EF Core、Dapper 等 ORM 框架会更加轻松,也能更精准地定位和解决数据访问层的性能问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/17 17:42:41

乌鲁木齐播音主持学校靠谱分享

引言在当今社会&#xff0c;播音主持不仅是一种职业选择&#xff0c;更是连接公众与信息的重要桥梁。随着新媒体的迅速发展&#xff0c;播音主持人才的需求日益增长。位于新疆首府的【乌鲁木齐市中科高级技工学校】以其独特的教育资源和培养体系&#xff0c;在播音主持领域内崭…

作者头像 李华
网站建设 2026/8/17 17:42:20

本地视频弹幕神器 BiliLocal 使用教程:离线看番也能满屏弹幕

本地视频弹幕神器 BiliLocal 使用教程&#xff1a;离线看番也能满屏弹幕 【免费下载链接】BiliLocal add danmaku to local videos 项目地址: https://gitcode.com/gh_mirrors/bi/BiliLocal 深夜加班回家&#xff0c;翻出硬盘里存了好几年的动画合集&#xff0c;想重温一…

作者头像 李华
网站建设 2026/8/17 17:40:56

使用TCP,数据就一定不会丢失吗?

TCP 是一个可靠的传输协议&#xff0c;那它一定能保证数据不丢失吗&#xff1f;这次&#xff0c;就跟大家探讨这个问题。数据包的发送流程首先&#xff0c;我们两个手机的绿皮聊天软件客户端&#xff0c;要通信&#xff0c;中间会通过它们家服务器。大概长这样。聊天软件三端通…

作者头像 李华
网站建设 2026/8/17 17:39:28

Steam成就管理器SAM快速上手:3分钟解锁全成就的完整指南

Steam成就管理器SAM快速上手&#xff1a;3分钟解锁全成就的完整指南 【免费下载链接】SteamAchievementManager A manager for game achievements in Steam. 项目地址: https://gitcode.com/gh_mirrors/st/SteamAchievementManager 你的Steam库里有这样一个游戏吗——全…

作者头像 李华