如何用C#(.NET) Azure Functions实现API数据直导SQL数据库?
兄弟,我来给你捋清楚怎么用C#/.NET直接把REST API返回的大量JSON数据怼进SQL数据库——你已经有API取数和Azure Functions写库的基础,其实就是把这俩的核心逻辑捏到一起,重点是针对大数据量做性能和稳定性优化,直接上干货:
核心思路
跳过Web服务中转,直接在C#程序(或Azure Functions)里完成「API请求→JSON解析→批量写入SQL」的闭环,核心是避免逐条插入,用高效的批量写入方案处理大数据量。
具体步骤与代码示例
1. 先装必要的NuGet包
这几个是刚需:
System.Net.Http:发送API请求System.Text.Json(或Newtonsoft.Json):JSON反序列化(原生库轻量,Newtonsoft兼容性更强,选你顺手的)Microsoft.Data.SqlClient:操作SQL数据库(比旧版System.Data.SqlClient更推荐,支持最新SQL特性)
2. 把API返回的JSON映射成C#实体
先定义和API返回结构匹配的实体类,比如API返回的是用户列表:
// 假设API返回格式:{"data": [{"id":1,"name":"张三","email":"zhangsan@example.com"},...]} public class ApiResponse<T> { public List<T> Data { get; set; } } public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } }
3. 从API拉取数据(流式处理省内存)
大数据量别一次性把所有JSON加载到内存,用流式读取+反序列化:
public async Task<ApiResponse<User>> FetchApiDataAsync(string apiUrl) { using var httpClient = new HttpClient(); // 加API认证头,比如Bearer Token httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer YourApiToken"); // 流式读取API响应,避免内存爆了 using var stream = await httpClient.GetStreamAsync(apiUrl); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; return await JsonSerializer.DeserializeAsync<ApiResponse<User>>(stream, options); }
4. 批量写入SQL(重点!别逐条Insert)
针对大数据量,推荐两种方案:
方案一:SqlBulkCopy(性能天花板,超大量数据首选)
public async Task BulkInsertUsersAsync(List<User> users, string connectionString) { // 把List转成DataTable(SqlBulkCopy支持的格式) var dataTable = new DataTable(); dataTable.Columns.Add("Id", typeof(int)); dataTable.Columns.Add("Name", typeof(string)); dataTable.Columns.Add("Email", typeof(string)); foreach (var user in users) { dataTable.Rows.Add(user.Id, user.Name, user.Email); } using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); using var bulkCopy = new SqlBulkCopy(connection) { DestinationTableName = "Users", // 目标SQL表名 BatchSize = 1000 // 每批插入的数量,根据数据库性能调整 }; // 列映射(如果实体和SQL列名完全一致可以省略) bulkCopy.ColumnMappings.Add("Id", "UserId"); // 比如SQL列名是UserId,实体是Id bulkCopy.ColumnMappings.Add("Name", "UserName"); bulkCopy.ColumnMappings.Add("Email", "UserEmail"); await bulkCopy.WriteToServerAsync(dataTable); }
方案二:Table-Valued Parameters(TVP,中等数据量更灵活)
先在SQL里定义自定义表类型:
CREATE TYPE UserTableType AS TABLE ( UserId INT, UserName NVARCHAR(50), UserEmail NVARCHAR(100) );
然后C#代码调用:
public async Task InsertUsersWithTvpAsync(List<User> users, string connectionString) { var tvp = new DataTable(); tvp.Columns.Add("UserId", typeof(int)); tvp.Columns.Add("UserName", typeof(string)); tvp.Columns.Add("UserEmail", typeof(string)); foreach (var user in users) { tvp.Rows.Add(user.Id, user.Name, user.Email); } using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); using var command = new SqlCommand( "INSERT INTO Users (UserId, UserName, UserEmail) SELECT UserId, UserName, UserEmail FROM @UserTable", connection ); command.Parameters.Add(new SqlParameter("@UserTable", SqlDbType.Structured) { TypeName = "UserTableType", Value = tvp }); await command.ExecuteNonQueryAsync(); }
5. 整合到Azure Functions(或控制台程序)
如果用Azure Functions,直接把逻辑塞进去,比如定时触发同步:
public class ApiToSqlSyncFunction { private readonly IConfiguration _configuration; public ApiToSqlSyncFunction(IConfiguration configuration) { _configuration = configuration; } [FunctionName("ApiToSqlSync")] public async Task Run([TimerTrigger("0 0 2 * * *")] TimerInfo myTimer, ILogger log) { log.LogInformation("Starting API to SQL sync job"); var apiUrl = _configuration["ApiSettings:Url"]; var connectionString = _configuration["ConnectionStrings:SqlDb"]; // 1. 拉取API数据 var apiResponse = await FetchApiDataAsync(apiUrl); if (apiResponse?.Data == null || !apiResponse.Data.Any()) { log.LogWarning("No data fetched from API"); return; } // 2. 批量写入SQL await BulkInsertUsersAsync(apiResponse.Data, connectionString); log.LogInformation($"Successfully inserted {apiResponse.Data.Count} records into SQL"); } // 把上面的FetchApiDataAsync和BulkInsertUsersAsync方法放这里 }
大数据量额外优化建议
- 分批请求API:如果API支持分页(比如page、pageSize参数),别一次性拉全量,分批次请求+写入,避免内存溢出。
- 流式边读边写:如果数据大到连DataTable都装不下,可以用
IDataReader配合SqlBulkCopy,边读API数据流边写SQL,完全不占内存。 - 事务保护:用
SqlTransaction包裹写入逻辑,失败时回滚,保证数据一致性。 - 临时禁用索引:写入前禁用SQL表的非聚集索引,写完再重建,能大幅提升写入速度。
- 错误重试:用Polly库加重试逻辑,处理API超时、SQL写入失败的情况,保证任务稳定性。
内容的提问来源于stack exchange,提问作者adlisval
相关产品推荐
相关产品推荐

