使用flutter的sqflite时报错database_closed
Error database_closed when using flutter's sqflite
我尝试使用 sqflite 保存一些数据,例如我的 class 电影,但是当我尝试插入或查询数据库时,看到这条消息:
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: DatabaseException(error database_closed)
我的MovieBloc
class:
List<Movie> _movies = new List<Movie> ();
class MoviesBloc implements BaseBloc {
final _moviesController = StreamController<List<Movie>>();
Database moviesDB;
String _moviesPath;
Stream<List<Movie>> get moviesStream => _moviesController.stream;
List<Movie> get movies => _movies;
int getLengthMovieList() {
return _movies.length;
}
clearMovieList() {
_movies.clear();
}
Future<void> openMovieDB({String dbName:'movies.db'}) async {
var databasesPath = await getDatabasesPath();
_moviesPath = join(databasesPath, dbName);
moviesDB = await openDatabase(_moviesPath, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
'CREATE TABLE movies (Id INTEGER PRIMARY KEY AUTOINCREMENT, Title TEXT NOT NULL, imdbRating TEXT, Poster TEXT, Plot TEXT, Saved INTEGER DEFAULT 0)');
});
}
Future<void> closeMovieDB() async => moviesDB.close();
void dispose() {
_moviesController.close();
}
}
我的MovieProvider
class:
class MovieProvider extends MoviesBloc {
String _tableName = 'movies';
Future<Movie> insert(Movie movie, {conflictAlgorithm: ConflictAlgorithm.ignore}) async {
await moviesDB.insert(_tableName, movie.toMap(), conflictAlgorithm: conflictAlgorithm);
return movie;
}
Future<bool> insertAll(List<Movie> movies) async {
await Future.wait(movies.map((movie) async {
await this.insert(movie);
}
));
return true;
}
Future<List<Movie>> paginate(int page, {int limit: 15}) async {
print('in Paginate to SQLite');
List<Map> maps = await moviesDB.query(_tableName,
columns: ['Id', 'Title', 'imdbRating', 'Poster', 'Plot', 'Saved'],
limit: limit,
offset: page == 1 ? 0 : ((page -1) * limit)
);
List<Movie> movies = new List<Movie> ();
if (maps.length > 0) {
maps.map((movie) {
movies.add(Movie.fromJson(movie));
}
);
}
return movies;
}
}
我的 save
sqflite 方法:
static Future<bool> saveAllMoviesIntoSqlite(List<Movie> movies) async {
var db = new MovieProvider();
await db.openMovieDB();
await db.insertAll(movies);
await db.closeMovieDB();
return true;
}
我的 load
来自 sqflite 的方法:
static Future<Map> getAllMoviesFromSqlite(int page) async {
var db = new MovieProvider();
await db.openMovieDB();
List<Movie> movies = new List<Movie> ();
movies = await db.paginate(page);
await db.closeMovieDB();
return {
"currentPage": page,
"movies": movies
};
}
- 我观察到
insertAll
方法 MovieProvider
class 用于将 movies
列表中的任何电影插入带有 await 和 async 的 sq:
Future<bool> insertAll(List<Movie> movies) async {
await Future.wait(movies.map((movie) async {
await this.insert(movie);
}
));
return true;
}
- 我尝试
close
和 open
数据库有时顺序和其他播放 close
和 open
数据库 ...
我的日志:
I/flutter ( 1617): in Paginate to SQLite
E/flutter ( 1617): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: DatabaseException(error database_closed)
E/flutter ( 1617): #0 SqfliteDatabaseMixin.checkNotClosed (package:sqflite_common/src/database_mixin.dart:282:7)
E/flutter ( 1617): #1 SqfliteDatabaseExecutorMixin._rawQuery (package:sqflite_common/src/database_mixin.dart:125:8)
E/flutter ( 1617): #2 SqfliteDatabaseExecutorMixin.query (package:sqflite_common/src/database_mixin.dart:110:12)
E/flutter ( 1617): #3 MovieProvider.paginate (package:umdb/bloc/movie_provider.dart:24:38)
E/flutter ( 1617): #4 MovieService.getAllMoviesFromSqlite (package:umdb/services/movie_service.dart:54:23)
E/flutter ( 1617): <asynchronous suspension>
E/flutter ( 1617): #5 MovieService.getSavedFromSQ (package:umdb/services/movie_service.dart:95:26)
E/flutter ( 1617): #6 MovieService.fetchSavedMovies (package:umdb/services/movie_service.dart:105:5)
E/flutter ( 1617): <asynchronous suspension>
E/flutter ( 1617): #7 MovieDetailState.build.<anonymous closure>.<anonymous closure> (package:umdb/ui_widgets/movie_detail.dart:168:42)
E/flutter ( 1617): #8 State.setState (package:flutter/src/widgets/framework.dart:1240:30)
E/flutter ( 1617): #9 MovieDetailState.build.<anonymous closure> (package:umdb/ui_widgets/movie_detail.dart:142:27)
E/flutter ( 1617): #10 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
E/flutter ( 1617): #11 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
E/flutter ( 1617): #12 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
E/flutter ( 1617): #13 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:256:7)
E/flutter ( 1617): #14 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:158:27)
E/flutter ( 1617): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:224:20)
E/flutter ( 1617): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
E/flutter ( 1617): #17 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
E/flutter ( 1617): #18 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
E/flutter ( 1617): #19 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
E/flutter ( 1617): #20 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter ( 1617): #21 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 1617): #22 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter ( 1617): #23 _invoke1 (dart:ui/hooks.dart:267:10)
E/flutter ( 1617): #24 _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)
请帮我解决一下
处理opening/closing数据库非常困难。确实有很多情况你可能会访问一个关闭的数据库,更糟糕的是,如果你打开同一个数据库两次,你得到的是同一个实例,所以第一次关闭将关闭数据库。
我个人建议保持数据库打开。
如果您需要处理多个数据库并且 open/close 它们用于短期操作,请确保您拥有适当的 mutex/lock 机制,以便您可以控制数据库的方式 opened/accessed/closed 而无需任何操作尝试同时访问同一个数据库的其他方法(好的,那部分不清楚抱歉)。
类似的东西(虽然我真的不推荐每次都opening/closing):
import 'package:synchronized/synchronized.dart';
final static _lock = Lock();
static Future<bool> saveAllMoviesIntoSqlite(List<Movie> movies) async {
return _lock.synchronized(() {
var db = new MovieProvider();
await db.openMovieDB();
await db.insertAll(movies);
await db.closeMovieDB();
return true;
});
}
static Future<Map> getAllMoviesFromSqlite(int page) async {
return _lock.synchronized(() {
var db = new MovieProvider();
await db.openMovieDB();
List<Movie> movies = new List<Movie> ();
movies = await db.paginate(page);
await db.closeMovieDB();
return {
"currentPage": page,
"movies": movies
};
});
}
您需要在关闭数据库时为您的数据库实例设置空值。否则它将始终 return 旧实例。
Future close() async {
final db = await instance.database;
_database = null;
return db.close();
}
我尝试使用 sqflite 保存一些数据,例如我的 class 电影,但是当我尝试插入或查询数据库时,看到这条消息:
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: DatabaseException(error database_closed)
我的MovieBloc
class:
List<Movie> _movies = new List<Movie> ();
class MoviesBloc implements BaseBloc {
final _moviesController = StreamController<List<Movie>>();
Database moviesDB;
String _moviesPath;
Stream<List<Movie>> get moviesStream => _moviesController.stream;
List<Movie> get movies => _movies;
int getLengthMovieList() {
return _movies.length;
}
clearMovieList() {
_movies.clear();
}
Future<void> openMovieDB({String dbName:'movies.db'}) async {
var databasesPath = await getDatabasesPath();
_moviesPath = join(databasesPath, dbName);
moviesDB = await openDatabase(_moviesPath, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
'CREATE TABLE movies (Id INTEGER PRIMARY KEY AUTOINCREMENT, Title TEXT NOT NULL, imdbRating TEXT, Poster TEXT, Plot TEXT, Saved INTEGER DEFAULT 0)');
});
}
Future<void> closeMovieDB() async => moviesDB.close();
void dispose() {
_moviesController.close();
}
}
我的MovieProvider
class:
class MovieProvider extends MoviesBloc {
String _tableName = 'movies';
Future<Movie> insert(Movie movie, {conflictAlgorithm: ConflictAlgorithm.ignore}) async {
await moviesDB.insert(_tableName, movie.toMap(), conflictAlgorithm: conflictAlgorithm);
return movie;
}
Future<bool> insertAll(List<Movie> movies) async {
await Future.wait(movies.map((movie) async {
await this.insert(movie);
}
));
return true;
}
Future<List<Movie>> paginate(int page, {int limit: 15}) async {
print('in Paginate to SQLite');
List<Map> maps = await moviesDB.query(_tableName,
columns: ['Id', 'Title', 'imdbRating', 'Poster', 'Plot', 'Saved'],
limit: limit,
offset: page == 1 ? 0 : ((page -1) * limit)
);
List<Movie> movies = new List<Movie> ();
if (maps.length > 0) {
maps.map((movie) {
movies.add(Movie.fromJson(movie));
}
);
}
return movies;
}
}
我的 save
sqflite 方法:
static Future<bool> saveAllMoviesIntoSqlite(List<Movie> movies) async {
var db = new MovieProvider();
await db.openMovieDB();
await db.insertAll(movies);
await db.closeMovieDB();
return true;
}
我的 load
来自 sqflite 的方法:
static Future<Map> getAllMoviesFromSqlite(int page) async {
var db = new MovieProvider();
await db.openMovieDB();
List<Movie> movies = new List<Movie> ();
movies = await db.paginate(page);
await db.closeMovieDB();
return {
"currentPage": page,
"movies": movies
};
}
- 我观察到
insertAll
方法MovieProvider
class 用于将movies
列表中的任何电影插入带有 await 和 async 的 sq:
Future<bool> insertAll(List<Movie> movies) async { await Future.wait(movies.map((movie) async { await this.insert(movie); } )); return true; }
- 我尝试
close
和open
数据库有时顺序和其他播放close
和open
数据库 ...
我的日志:
I/flutter ( 1617): in Paginate to SQLite
E/flutter ( 1617): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: DatabaseException(error database_closed)
E/flutter ( 1617): #0 SqfliteDatabaseMixin.checkNotClosed (package:sqflite_common/src/database_mixin.dart:282:7)
E/flutter ( 1617): #1 SqfliteDatabaseExecutorMixin._rawQuery (package:sqflite_common/src/database_mixin.dart:125:8)
E/flutter ( 1617): #2 SqfliteDatabaseExecutorMixin.query (package:sqflite_common/src/database_mixin.dart:110:12)
E/flutter ( 1617): #3 MovieProvider.paginate (package:umdb/bloc/movie_provider.dart:24:38)
E/flutter ( 1617): #4 MovieService.getAllMoviesFromSqlite (package:umdb/services/movie_service.dart:54:23)
E/flutter ( 1617): <asynchronous suspension>
E/flutter ( 1617): #5 MovieService.getSavedFromSQ (package:umdb/services/movie_service.dart:95:26)
E/flutter ( 1617): #6 MovieService.fetchSavedMovies (package:umdb/services/movie_service.dart:105:5)
E/flutter ( 1617): <asynchronous suspension>
E/flutter ( 1617): #7 MovieDetailState.build.<anonymous closure>.<anonymous closure> (package:umdb/ui_widgets/movie_detail.dart:168:42)
E/flutter ( 1617): #8 State.setState (package:flutter/src/widgets/framework.dart:1240:30)
E/flutter ( 1617): #9 MovieDetailState.build.<anonymous closure> (package:umdb/ui_widgets/movie_detail.dart:142:27)
E/flutter ( 1617): #10 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
E/flutter ( 1617): #11 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
E/flutter ( 1617): #12 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
E/flutter ( 1617): #13 BaseTapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:256:7)
E/flutter ( 1617): #14 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:158:27)
E/flutter ( 1617): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:224:20)
E/flutter ( 1617): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
E/flutter ( 1617): #17 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
E/flutter ( 1617): #18 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
E/flutter ( 1617): #19 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
E/flutter ( 1617): #20 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter ( 1617): #21 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter ( 1617): #22 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter ( 1617): #23 _invoke1 (dart:ui/hooks.dart:267:10)
E/flutter ( 1617): #24 _dispatchPointerDataPacket (dart:ui/hooks.dart:176:5)
请帮我解决一下
处理opening/closing数据库非常困难。确实有很多情况你可能会访问一个关闭的数据库,更糟糕的是,如果你打开同一个数据库两次,你得到的是同一个实例,所以第一次关闭将关闭数据库。
我个人建议保持数据库打开。
如果您需要处理多个数据库并且 open/close 它们用于短期操作,请确保您拥有适当的 mutex/lock 机制,以便您可以控制数据库的方式 opened/accessed/closed 而无需任何操作尝试同时访问同一个数据库的其他方法(好的,那部分不清楚抱歉)。
类似的东西(虽然我真的不推荐每次都opening/closing):
import 'package:synchronized/synchronized.dart';
final static _lock = Lock();
static Future<bool> saveAllMoviesIntoSqlite(List<Movie> movies) async {
return _lock.synchronized(() {
var db = new MovieProvider();
await db.openMovieDB();
await db.insertAll(movies);
await db.closeMovieDB();
return true;
});
}
static Future<Map> getAllMoviesFromSqlite(int page) async {
return _lock.synchronized(() {
var db = new MovieProvider();
await db.openMovieDB();
List<Movie> movies = new List<Movie> ();
movies = await db.paginate(page);
await db.closeMovieDB();
return {
"currentPage": page,
"movies": movies
};
});
}
您需要在关闭数据库时为您的数据库实例设置空值。否则它将始终 return 旧实例。
Future close() async {
final db = await instance.database;
_database = null;
return db.close();
}