1. 项目概述
"SqlSugar完结篇"这个标题背后,是一个关于C#数据库操作框架的深度技术总结。作为.NET生态中广受欢迎的ORM工具,SqlSugar以其轻量级、高性能和易用性著称。这个"完结篇"意味着我们将对SqlSugar的核心功能、高级用法和实战经验进行全面梳理。
在实际开发中,我发现很多团队虽然在使用SqlSugar,但往往只停留在基础CRUD层面,未能充分发挥其潜力。本文将带你深入理解SqlSugar的架构设计,掌握其高级特性,并分享我在企业级项目中积累的最佳实践。
2. 核心功能解析
2.1 基础CRUD的进阶用法
SqlSugar的基础CRUD操作看似简单,但其中蕴含着不少优化技巧:
csharp复制// 标准查询示例
var list = db.Queryable<Student>()
.Where(it => it.Age > 18)
.OrderBy(it => it.CreateTime, OrderByType.Desc)
.ToList();
这里有几个关键点需要注意:
- 延迟执行机制:直到调用ToList()等终结方法时才会真正执行SQL
- 表达式树解析:Where条件会被转换为参数化查询,防止SQL注入
- 智能缓存:相同的查询条件会自动利用缓存
提示:对于高频查询,建议使用WithCache()方法显式启用缓存,并合理设置缓存过期时间。
2.2 事务处理的正确姿势
事务管理是数据库操作的核心难点之一。SqlSugar提供了多种事务控制方式:
csharp复制// 方式1:使用Ado事务
db.Ado.BeginTran();
try {
// 业务操作
db.Ado.CommitTran();
} catch {
db.Ado.RollbackTran();
}
// 方式2:使用Sugar封装的简易事务
db.UseTran(() => {
// 业务操作
});
在实际项目中,我推荐第二种方式,因为它:
- 自动处理异常回滚
- 支持异步操作
- 嵌套事务时会自动升级为分布式事务
3. 高级特性实战
3.1 分库分表解决方案
面对海量数据时,分库分表是必选项。SqlSugar提供了完善的分表支持:
csharp复制// 按月分表查询
var list = db.Queryable<Order>()
.SplitTable(tabs => tabs.SplitWhere(it => it.CreateTime))
.Where(it => it.CreateTime > DateTime.Now.AddMonths(-3))
.ToList();
关键配置项:
- SplitTableConfig:定义分表规则
- SplitTableAttribute:实体类标注分表字段
- SplitTableService:自定义分表策略
经验:对于订单类业务,建议按时间范围分表,同时考虑冷热数据分离策略。
3.2 读写分离实现
高并发场景下,读写分离能显著提升系统吞吐量:
csharp复制// 多数据源配置
var db = new SqlSugarScope(new List<ConnectionConfig>(){
new ConnectionConfig(){ ConfigId="write", ConnectionString=writeConn },
new ConnectionConfig(){ ConfigId="read1", ConnectionString=readConn1 },
new ConnectionConfig(){ ConfigId="read2", ConnectionString=readConn2 }
},
db => {
// 读写分离策略
db.Aop.OnLogExecuting = (sql, pars) => {
if(sql.StartsWith("SELECT")) {
db.ChangeDatabase("read1"); // 随机选择读库
}
};
});
最佳实践:
- 写操作走主库,读操作走从库
- 考虑使用连接池管理多个从库连接
- 重要业务可配置强制走主库
4. 性能优化指南
4.1 批量操作性能对比
不同批量操作方式的性能差异显著:
| 操作方式 | 1万条数据耗时 | 内存占用 |
|---|---|---|
| 单条插入 | 12.8s | 高 |
| BulkCopy | 0.8s | 低 |
| 批量插入 | 1.2s | 中 |
推荐使用SqlSugar的BulkCopy功能:
csharp复制db.Fastest<Order>().BulkCopy(orders);
注意事项:
- 需要数据库支持BulkCopy协议
- 大批量操作建议分批次执行
- 考虑使用并行处理提升效率
4.2 查询优化技巧
- 只查询需要的字段:
csharp复制db.Queryable<Order>()
.Select(it => new { it.Id, it.OrderNo })
.ToList();
- 合理使用索引提示:
csharp复制db.Queryable<Order>()
.With(SqlWith.NoLock)
.ToList();
- 避免N+1查询:
csharp复制// 错误示例
var orders = db.Queryable<Order>().ToList();
foreach(var o in orders) {
o.Items = db.Queryable<OrderItem>().Where(it => it.OrderId == o.Id).ToList();
}
// 正确做法
var orders = db.Queryable<Order>()
.Includes(it => it.Items)
.ToList();
5. 企业级应用方案
5.1 多租户架构实现
SaaS系统中,多租户是常见需求。SqlSugar提供了优雅的实现方案:
csharp复制// 租户过滤器
db.QueryFilter.Add(new TableFilterItem<Order>(it => it.TenantId == currentTenantId));
// 自动处理租户ID
db.Aop.OnInsertExecuting = (entity, _) => {
if(entity is ITenant tenant) {
tenant.TenantId = currentTenantId;
}
};
关键设计点:
- 共享数据库,隔离Schema
- 全局查询过滤器
- 租户上下文管理
5.2 审计日志集成
合规性要求下,数据变更审计是刚需:
csharp复制db.Aop.OnLogExecuting = (sql, pars) => {
var audit = new AuditLog {
Sql = sql,
Parameters = JsonConvert.SerializeObject(pars),
ExecuteTime = DateTime.Now
};
// 异步写入日志存储
Task.Run(() => SaveAuditLog(audit));
};
进阶方案:
- 使用CDC捕获数据变更
- 集成ELK实现日志分析
- 敏感数据脱敏处理
6. 常见问题排查
6.1 连接池耗尽问题
症状:系统运行一段时间后出现"Timeout expired. The timeout period elapsed..."错误。
解决方案:
- 检查是否有连接未释放
csharp复制// 错误示例
public List<Order> GetOrders() {
var db = new SqlSugarClient(conn);
return db.Queryable<Order>().ToList();
// db未释放
}
// 正确做法
using(var db = new SqlSugarClient(conn)) {
return db.Queryable<Order>().ToList();
}
- 调整连接池配置:
csharp复制new ConnectionConfig {
ConnectionString = connStr,
PoolMin = 5, // 最小连接数
PoolMax = 100, // 最大连接数
IsAutoCloseConnection = true // 自动释放连接
}
6.2 性能突然下降
可能原因及排查步骤:
- 检查数据库监控,确认是否出现锁等待
- 分析慢查询日志,优化相关SQL
- 检查是否触发了分表策略变更
- 确认网络状况是否正常
诊断工具推荐:
- SqlSugar的AOP日志
- SQL Server Profiler
- 应用性能监控(APM)工具
7. 扩展与集成
7.1 与Dapper性能对比
在特定场景下的基准测试结果:
| 场景 | SqlSugar(ms) | Dapper(ms) |
|---|---|---|
| 简单查询 | 12 | 10 |
| 复杂联查 | 45 | 52 |
| 批量插入 | 800 | 1200 |
| 事务操作 | 22 | 18 |
选择建议:
- 简单场景:Dapper略优
- 复杂业务:SqlSugar更易维护
- 需要快速开发:SqlSugar更高效
7.2 与EF Core的互操作
实际项目中可以混合使用:
csharp复制// 在EF Core中使用SqlSugar
var orders = context.Orders.FromSqlRaw(
"SELECT * FROM Orders WHERE CreateTime > @p0",
DateTime.Now.AddDays(-7)
).ToList();
// 在SqlSugar中调用存储过程
var result = db.Ado.UseStoredProcedure().GetDataTable("sp_GetSalesReport");
集成方案:
- 共用连接字符串
- 统一事务管理
- 共享DTO模型
8. 最佳实践总结
经过多个企业级项目的验证,我总结了以下SqlSugar使用原则:
- 配置标准化:
csharp复制// 推荐配置
var config = new ConnectionConfig {
ConnectionString = connStr,
DbType = DbType.SqlServer,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
MoreSettings = new ConnMoreSettings {
IsWithNoLockQuery = true, // 默认NOLOCK
SqlServerCodeFirstNvarchar = true // 字符串默认NVARCHAR
}
};
- 代码组织规范:
- 数据访问层单独项目
- 每个实体类对应一个Repository
- 使用工作单元模式管理事务
- 监控与调优:
- 记录慢查询日志
- 定期分析执行计划
- 监控连接池使用情况
最后分享一个实用技巧:对于超大规模数据导出,可以结合SqlSugar的分页查询和流式处理:
csharp复制var pageIndex = 1;
while(true) {
var data = db.Queryable<Order>()
.OrderBy(it => it.Id)
.ToPageList(pageIndex, 1000);
if(data.Count == 0) break;
ProcessData(data);
pageIndex++;
}
这种方式可以避免内存溢出,同时保持较好的性能。