1. 引言:为什么需要掌握原生数据库操作?
在日常开发中,我们经常需要与数据库打交道。虽然现在流行各种ORM框架(比如Entity Framework),但掌握原生ADO.NET操作就像厨师熟悉刀工一样重要。当你需要处理大批量数据、优化性能或维护遗留系统时,System.Data.SqlClient这个"老伙计"依然是最可靠的选择。
2. 环境准备与基础操作
2.1 项目配置
确保在.csproj文件中包含以下NuGet包引用:
<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
2.2 基础插入示例
using System.Data.SqlClient;
public class BasicInsertExample
{
public void InsertUser(string userName, string email)
{
// 连接字符串配置(实际项目建议使用配置管理)
string connectionString = "Server=.;Database=TestDB;Integrated Security=True;";
// 使用using确保资源释放
using (SqlConnection connection = new SqlConnection(connectionString))
{
// 构造插入语句
string sql = "INSERT INTO Users (UserName, Email) VALUES (@UserName, @Email)";
// 创建命令对象
using (SqlCommand command = new SqlCommand(sql, connection))
{
// 添加参数化查询参数
command.Parameters.AddWithValue("@UserName", userName);
command.Parameters.AddWithValue("@Email", email);
// 打开连接
connection.Open();
// 执行非查询操作
int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine($"成功插入{rowsAffected}条记录");
}
}
}
}
3. 进阶操作技巧
3.1 批量插入优化
public void BulkInsertUsers(List<User> users)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// 使用事务确保批量操作原子性
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
foreach (var user in users)
{
using (SqlCommand command = new SqlCommand(
"INSERT INTO Users (UserName, Email) VALUES (@u, @e)",
connection,
transaction))
{
command.Parameters.AddWithValue("@u", user.Name);
command.Parameters.AddWithValue("@e", user.Email);
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
3.2 获取插入后的自增ID
public int InsertWithReturnId(string userName)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
string sql = @"INSERT INTO Users (UserName)
OUTPUT INSERTED.UserId
VALUES (@name)";
SqlCommand cmd = new SqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@name", userName);
conn.Open();
return (int)cmd.ExecuteScalar();
}
}
4. 关联技术:与Entity Framework的配合
4.1 混合使用场景
// 在EF Core中执行原生SQL
context.Database.ExecuteSqlRaw(
"INSERT INTO AuditLogs (Action, Timestamp) VALUES ({0}, {1})",
"UserCreated",
DateTime.Now);
5. 应用场景分析
- 数据采集系统:需要高频次写入传感器数据
- 业务系统初始化:创建基础数据时对性能有要求
- 日志记录系统:需要保证写入成功率的同时不影响主业务
6. 技术优缺点对比
优点:
- 直接操作底层协议,性能最优
- 完全掌控SQL执行细节
- 适合复杂事务处理
缺点:
- 需要手动处理连接池和资源释放
- SQL注入防护依赖开发人员自觉
- 数据类型转换需要手动处理
7. 关键注意事项
- 防注入原则:永远使用参数化查询
- 连接管理:最大连接数建议配置为(核心数*2)+1
- 超时设置:根据业务需求设置合理的CommandTimeout
- 错误处理:建议实现重试机制(特别是网络不稳定的环境)
8. 性能优化技巧
- 批量操作时使用SqlBulkCopy
- 合理设置Packet Size(默认4096字节)
- 启用MultipleActiveResultSets(MARS)特性
- 使用异步API(ExecuteNonQueryAsync)
9. 完整实战示例
public class AdvancedDataInserter
{
private readonly string _connString;
public AdvancedDataInserter(string connectionString)
{
_connString = connectionString;
}
public async Task<int> SafeInsertAsync(UserData data)
{
using (var conn = new SqlConnection(_connString))
{
await conn.OpenAsync();
var command = conn.CreateCommand();
command.CommandText = @"
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO Users (...) VALUES (...);
INSERT INTO Profiles (...) VALUES (...);
COMMIT TRANSACTION
RETURN 1
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
THROW
END CATCH";
// 添加参数省略...
return await command.ExecuteNonQueryAsync();
}
}
}
10. 总结与展望
通过本文的讲解,我们不仅掌握了使用System.Data.SqlClient进行数据插入的基础和进阶技巧,还了解了如何在不同场景下做出技术选型。虽然现代开发中ORM框架越来越普及,但在处理复杂事务、性能敏感场景时,直接使用ADO.NET仍然是不可替代的解决方案。