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

Flutter切换页面时出现Sqflite database_closed数据库关闭报错求助

问题原因排查
  • 核心原因:你的DbHelper中_db是全局静态单例实例,若你在任意页面的dispose等生命周期中主动调用了Database.close()方法,单例就会被标记为关闭状态,后续其他页面再复用这个已经关闭的实例就会抛出database_closed异常。
  • 附加逻辑问题:你当前initDb方法中每次初始化都会删除已有数据库、重写assets中的预置库,若单例被销毁重建,会导致所有用户产生的运行时数据丢失,同时极端情况下删库重写的过程中触发读写也会报错。
  • 小概率场景:你在页面触发数据库异步查询后,还未等待返回就销毁了页面上下文,异步回调中持有了已经被回收的数据库实例引用。
修复方案

1. 移除所有主动关闭数据库的代码

全局检索项目中所有调用close()方法操作数据库实例的代码,全部删除。正常应用生命周期内不需要主动关闭sqflite数据库,应用退出时系统会自动回收相关资源。

2. 修正DbHelper的初始化逻辑

删除每次初始化删库的逻辑,增加本地数据库是否存在的判断,只有本地数据库不存在的时候才拷贝assets中的预置库,避免数据丢失,修改后的参考代码如下:

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:bankingapp/models/coin.dart';
import 'package:bankingapp/models/histories.dart';
import 'package:flutter/services.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DbHelper {
  static Database? _db;

  Future<Database> get db async {
    // 增加实例打开状态校验,被关闭后自动重新初始化
    if (_db == null || !_db!.isOpen) {
      _db = await initDb();
    }
    return _db!;
  }

  Future<Database> initDb() async {
    var dbFolder = await getDatabasesPath();
    String path = join(dbFolder, 'app.db');

    // 仅本地数据库不存在时拷贝预置库,删除原有的强制删库逻辑
    bool dbExists = await databaseExists(path);
    if (!dbExists) {
      try {
        await Directory(dirname(path)).create(recursive: true);
      } catch (_) {}
      ByteData data = await rootBundle.load(join("assets/database", "bankingapp.db"));
      List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await File(path).writeAsBytes(bytes, flush: true);
    }

    return await openDatabase(path);
  }

  Future<List<Histories>> getHistories() async {
    var dbClient = await db;
    var result = await dbClient.rawQuery("SELECT * FROM Histories");
    return result.map((data) => Histories.fromMap(data)).toList();
  }

  Future<List<Coins>> getCoins() async {
    var dbClient = await db;
    var result = await dbClient.rawQuery("SELECT * FROM Coins");
    return result.map((data) => Coins.fromMap(data)).toList();
  }
}

3. 适配数据库版本迭代(可选)

如果后续需要更新预置的数据库、或者做表结构变更,可以在openDatabase方法中传入version参数和onUpgrade回调,处理版本升级逻辑,避免覆盖用户本地数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 05:57:04