Agent Skills
› tekartik/sqflite
› sqflite-common-ffi-async-factory
sqflite-common-ffi-async-factory
GitHub指导在桌面端使用sqflite_common_fi_async库,通过sqlite_async实现读写并发,避免读取阻塞。说明API用法、与标准ffi的区别、只读回退及限制。
Trigger Scenarios
需要在Dart VM或Flutter桌面端进行SQLite数据库操作
需要实现高并发读取而不被写入阻塞
Install
npx skills add tekartik/sqflite --skill sqflite-common-ffi-async-factory -g -y
SKILL.md
Frontmatter
{
"name": "sqflite-common-ffi-async-factory",
"description": "Use when using package:sqflite_common_ffi_async, the experimental sqflite DatabaseFactory built on sqlite_async (PowerSync) for desktop and the Dart VM: databaseFactoryFfiAsync, databaseFactoryFfiAsyncTest, readTransaction and concurrent reads, how it differs from sqflite_common_ffi (databaseFactoryFfi), what falls back to plain ffi (in-memory, read-only), and its limitations (no logger, singleInstance ignored, io only)."
}
sqflite_common_ffi_async: sqflite API on top of sqlite_async
package:sqflite_common_ffi_async exposes the sqflite DatabaseFactory /
Database API backed by package:sqlite_async (a connection pool with one
writer and several readers) instead of the single background isolate of
sqflite_common_ffi. Use it on Linux, macOS, Windows (Dart VM or Flutter
desktop) when reads must not wait behind writes. It is experimental (1.0.x).
import 'package:sqflite_common_ffi/sqflite_ffi.dart' show sqfliteFfiInit;
import 'package:sqflite_common_ffi_async/sqflite_ffi_async.dart';
Future<void> main() async {
sqfliteFfiInit();
var db = await databaseFactoryFfiAsync.openDatabase('example.db');
await db.execute('CREATE TABLE IF NOT EXISTS Product (id INTEGER PRIMARY KEY, title TEXT)');
await db.insert('Product', {'title': 'Product 1'});
print(await db.query('Product'));
await db.close();
}
Guidelines
- Depend on both
sqflite_common_ffi_asyncandsqflite_common_ffi(the async package delegates some operations to it). Importpackage:sqflite_common_ffi_async/sqflite_ffi_async.dart; it re-exportspackage:sqflite_common/sqflite.dart(Database,OpenDatabaseOptions,inMemoryDatabasePath, globaldatabaseFactory...).sqfliteFfiInitcomes frompackage:sqflite_common_ffi/sqflite_ffi.dart; call it once at startup (Windows setup, no-op elsewhere). - Public API:
databaseFactoryFfiAsync(tagffi_async) anddatabaseFactoryFfiAsyncTest(tagffi_async_test, a second independent factory instance for tests). Everything else is undersrc/. - The
DatabaseAPI (query,insert,transaction,batch,OpenDatabaseOptionscallbacks) is the standard sqflite one, documented by thesqflite/sqflite_commonskills. Code written againstDatabaseFactoryworks unchanged; only the factory differs. - What
sqlite_asyncadds:db.readTransaction((txn) async { ... })runs on a read connection concurrently with writes. Only reads are allowed inside: a write through thattxnthrows aDatabaseException("read transaction cannot be used for write"). On other sqflite implementationsreadTransactionis not supported, so keep it behind this factory.db.transaction(...)is asqlite_asyncwrite transaction. Severaltransactioncalls from different callers are queued by the pool, not by sqflite, so reads issued outside a transaction are not blocked by a running write transaction.
- Falls back to
databaseFactoryFfi(regular ffi, separate isolate):openDatabase(inMemoryDatabasePath): in-memory databases come fromsqflite_common_ffi(mainly for tests).openDatabase(path, options: OpenDatabaseOptions(readOnly: true)).deleteDatabase(path)andgetDatabasesPath()(default is<cwd>/.dart_tool/sqflite_common_ffi/databases, relative paths resolve there).
- The parent directory of a database file is created on open. Prefer absolute paths in applications.
- Limitations (from the package README and source):
singleInstanceis ignored:sqlite_asyncmanages opening/closing.- No logger support (
SqfliteDatabaseFactoryLoggerwrappers are not wired in). queryCursor/rawQueryCursorload the whole result set, no paging.- io only (
platforms: linux, macos, windows, android, ios); no web. Calling on the web throwsUnsupportedError. - After
close(), any call fails with adatabase_closederror.
- For unit tests prefer
databaseFactoryFfifromsqflite_common_ffi(seesqflite-common-ffi-testing) unless the test exercisesreadTransactionor concurrency behavior; then usedatabaseFactoryFfiAsyncTestwith a file path anddeleteDatabaseinsetUp.
Examples
Concurrent read during a long write transaction
import 'package:sqflite_common_ffi/sqflite_ffi.dart' show sqfliteFfiInit;
import 'package:sqflite_common_ffi_async/sqflite_ffi_async.dart';
Future<void> main() async {
sqfliteFfiInit();
var factory = databaseFactoryFfiAsync;
var db = await factory.openDatabase(
'concurrent.db',
options: OpenDatabaseOptions(
version: 1,
onCreate: (db, _) => db.execute(
'CREATE TABLE Item (id INTEGER PRIMARY KEY, name TEXT)',
),
),
);
var write = db.transaction((txn) async {
await txn.insert('Item', {'name': 'slow'});
await Future<void>.delayed(const Duration(milliseconds: 500));
await txn.insert('Item', {'name': 'write'});
});
// Runs on a reader connection while the write transaction is open.
var count = await db.readTransaction((txn) async {
var rows = await txn.rawQuery('SELECT COUNT(*) AS c FROM Item');
return rows.first['c'] as int;
});
await write;
print(count); // 0: the write transaction had not committed yet
await db.close();
}
Test with the dedicated test factory
@TestOn('vm')
library;
import 'package:sqflite_common_ffi/sqflite_ffi.dart' show sqfliteFfiInit;
import 'package:sqflite_common_ffi_async/sqflite_ffi_async.dart';
import 'package:test/test.dart';
void main() {
sqfliteFfiInit();
final factory = databaseFactoryFfiAsyncTest;
const path = 'ffi_async_test.db';
setUp(() => factory.deleteDatabase(path));
test('version and insert', () async {
var db = await factory.openDatabase(
path,
options: OpenDatabaseOptions(
version: 1,
onCreate: (db, _) => db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY)'),
),
);
expect(await db.getVersion(), 1);
expect(await db.insert('Test', {'id': 1}), 1);
await db.close();
});
}
Selecting the factory per platform
import 'dart:io';
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:sqflite_common_ffi_async/sqflite_ffi_async.dart';
DatabaseFactory pickFactory() {
sqfliteFfiInit();
if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) {
return databaseFactoryFfiAsync;
}
return databaseFactoryFfi;
}
Common mistakes
- Writing inside
readTransaction: throws. Usetransactionfor writes. - Using
readTransactionwithdatabaseFactoryFfior thesqfliteplugin: not supported there. - Expecting
singleInstance: truesemantics (sameDatabaseobject for the same path): the async factory does not honor it. - Forgetting
sqfliteFfiInit()on Windows. - Using it on the web: use
sqflite_common_ffi_webinstead. - Depending only on
sqflite_common_ffi_asyncand importingsqflite_common_ffi/sqflite_ffi.darttransitively; declare both.
Version History
- aaabf90 Current 2026-09-22 03:37


