You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中使用sqflite插入HTTP Get获取的数据时无法存储全部记录

问题分析与解决方案

你遇到的核心问题是异步操作未被正确等待,导致数据库插入操作在未全部完成时就被中断了——这也是为什么HTTP能拿到149条数据,但只有101条插入成功的原因。

问题根源拆解

看你ApiProvider里的这段代码:

(res as List).map((product) {
  DatabaseHelper.db.insertProduct(NewProduct.fromJson(product));
}).toList();

这里的insertProduct是异步方法(返回Future),但你只是在map里调用它,却没有等待这些Future执行完毕。map只会生成一堆未被处理的Future,而你的getPro方法会直接返回,不会等所有插入完成。

当main函数里的await apiProvider.getAllProducts()执行完时,实际上大部分插入操作还在后台跑,而此时应用开始启动runApp,事件循环优先级转向UI渲染,部分未完成的插入操作就被中断了,所以只成功插入了最先完成的101条。

修复方案

方案1:等待所有单个插入完成

修改ApiProvider的getPro方法,用Future.wait等待所有插入操作完成:

class ApiProvider {
  Future<List<NewProduct>?> getPro() async {
    Response response = await Dio().get(Info.productUrl);
    var res = response.data;
    print("PRODUCT LENGTH-" + res.length.toString());
    
    // 用Future.wait等待所有插入Future完成
    await Future.wait((res as List).map((product) async {
      await DatabaseHelper.db.insertProduct(NewProduct.fromJson(product));
    }));
    
    // 返回转换后的产品列表(可选)
    return (res as List).map((product) => NewProduct.fromJson(product)).toList();
  }
}

同时,main函数里的deleteAllProduct也是异步操作,必须加await,否则可能删除还没完成就开始插入:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(backgroundHandler);
  DatabaseHelper.db.database;
  if (await InternetConnectionChecker().hasConnection) {
    print("INTERNERT AVAILABLE");
    // 等待删除操作完成
    await DatabaseHelper.db.deleteAllProduct();
    await apiProvider.getAllProducts();
    // 这里的延迟可以去掉了,因为已经等待所有插入完成
    runApp(MyApp());
  } else {
    print("NO INTERNET");
    runApp(NoConn());
  }
}

方案2:改用批量插入(更高效)

逐个插入149条数据效率较低,推荐用SQLite的批量操作来优化,同时避免异步等待的问题:
首先在DatabaseHelper里新增批量插入方法:

// 新增批量插入方法
Future<void> insertProducts(List<NewProduct> products) async {
  final db = await database;
  final batch = db.batch();
  for (var product in products) {
    batch.insert('SA_PRO_MASTER', product.toJson());
  }
  // 提交批量操作,noResult设为true可以忽略返回结果提升性能
  await batch.commit(noResult: true);
}

然后修改ApiProvider的getPro方法:

class ApiProvider {
  Future<List<NewProduct>?> getPro() async {
    Response response = await Dio().get(Info.productUrl);
    var res = response.data;
    print("PRODUCT LENGTH-" + res.length.toString());
    
    // 先把所有JSON转成NewProduct对象
    final productList = (res as List).map((product) => NewProduct.fromJson(product)).toList();
    // 调用批量插入
    await DatabaseHelper.db.insertProducts(productList);
    
    return productList;
  }
}

额外排查建议

为了避免无声失败,建议给数据库操作加上错误捕获:

// 修改单个插入方法
insertProduct(NewProduct listPro) async {
  final db = await database;
  try {
    final res = await db.insert('SA_PRO_MASTER', listPro.toJson());
    print("INSERT RES - " + res.toString());
    return res;
  } catch(e) {
    print("插入产品失败: ${listPro.sa_proid} - $e");
    rethrow; // 可以选择抛出错误或者处理
  }
}

这样如果有某个产品因为数据问题(比如NOT NULL字段为空)插入失败,你能在控制台看到具体错误。

内容的提问来源于stack exchange,提问作者Savan Nagda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 08:12:40