Flutter数据同步插件synchroflite的使用
Flutter数据同步插件synchroflite的使用
Dart实现的Conflict-free Replicated Data Types (CRDTs),提供Sqflite API。 基于Daniel Cachapa的工作。
该实现的范围是为了在drift_crdt中使用API。
此包实现了sql_crdt。
设置
等待异步函数完成非常重要,不这样做可能会导致各种奇怪的行为。
你可以通过在analysis_options.yaml
中激活unawaited_futures
linter警告来避免它们:
linter:
rules:
unawaited_futures: true
此包使用了sqflite。根据你打算运行代码的位置,需要一些额外的设置:
Android & iOS
synchroflite
使用了一些可能不在每个系统嵌入库中的最新Sqlite功能。
为了解决这个问题,你需要将sqlite3_flutter_libs包导入到你的项目中:
sqlite3_flutter_libs: ^0.5.12
桌面和服务器
在桌面和服务器上,Sqflite使用系统库,因此请确保已安装这些库。
在Debian, Raspbian, Ubuntu等系统上:
sudo apt install libsqlite3 libsqlite3-dev
在Fedora上:
sudo dnf install sqlite-devel
否则,请查看sqflite_common_ffi的说明。
Web
此包具有对Flutter Web的实验性支持,感谢sqflite_common_ffi_web。
为了使用此功能,你需要安装Sqlite3 Web二进制文件,从项目的根目录运行以下命令:
dart run sqflite_common_ffi_web:setup
使用
更多详细信息,请参阅example.dart。
特性和错误
请在issue tracker中提交特性请求和错误报告。
注意
此包并不实现完整的Sqflite API。它只实现了drift_crdt所需的API。如果你需要更多功能,请打开一个issue或PR。
示例代码
// Copyright 2023 Janez Stupar
// This code is based on Daniel Cachapa's work in sqlite_crdt:
// https://github.com/cachapa/sqlite_crdt
// SPDX-License-Identifier: Apache-2.0
import 'package:synchroflite/synchroflite.dart';
Future<void> main() async {
// 创建或加载数据库
final crdt = await Synchroflite.openInMemory(
version: 1,
onCreate: (db, version) async {
// 创建一个表
await db.execute('''
CREATE TABLE users (
id INTEGER NOT NULL,
name TEXT,
PRIMARY KEY (id)
)
''');
},
);
// 向数据库插入一条记录
await crdt.execute('''
INSERT INTO users (id, name)
VALUES (?1, ?2)
''', [1, 'John Doe']);
// 删除该记录
await crdt.execute('DELETE FROM users WHERE id = ?1', [1]);
// 合并远程数据集
await crdt.merge({
'users': [
{
'id': 2,
'name': 'Jane Doe',
'hlc': Hlc.now(generateNodeId()), // 使用当前节点生成的时间戳
},
],
});
// 查询语句很简单,但请注意:
// 1. CRDT列:hlc, modified, is_deleted
// 2. 先生Doe以is_deleted = 1的形式出现在结果中
final result = await crdt.query('SELECT * FROM users');
printRecords('SELECT * FROM users', result);
// 或许更好的查询是
final betterResult =
await crdt.query('SELECT id, name FROM users WHERE is_deleted = 0');
printRecords('SELECT id, name FROM users WHERE is_deleted = 0', betterResult);
// 我们也可以观察特定查询的结果,但请注意这可能效率低下,因为每次数据库更改都会重新运行观察查询
crdt.watch('SELECT id, name FROM users WHERE is_deleted = 0').listen((e) =>
printRecords(
'Watch: SELECT id, name FROM users WHERE is_deleted = 0', e));
// 更新数据库
await crdt.execute('''
UPDATE users SET name = ?1
WHERE id = ?2
''', ['Jane Doe 👍', 2]);
// 因为条目只是被标记为删除,所以撤销删除操作非常简单
await crdt.execute('''
UPDATE users SET is_deleted = ?1
WHERE id = ?2
''', [1, 1]);
// 在事务中执行多个写操作,以便它们获得相同的时间戳
await crdt.transaction((txn) async {
// 确保你使用事务对象(txn)
// 使用[crdt]会导致死锁
await txn.execute('''
INSERT INTO users (id, name)
VALUES (?1, ?2)
''', [3, 'Uncle Doe']);
await txn.execute('''
INSERT INTO users (id, name)
VALUES (?1, ?2)
''', [4, 'Grandma Doe']);
});
final timestamps =
await crdt.query('SELECT id, hlc, modified FROM users WHERE id > 2');
printRecords('SELECT id, hlc, modified FROM users WHERE id > 2', timestamps);
// 创建一个变更集以与另一个节点同步
final changeset = await crdt.getChangeset();
print('> 变更集大小: ${changeset.recordCount} 条记录');
changeset.forEach((key, value) {
print(key);
for (var e in value) {
print(' $e');
}
});
}
void printRecords(String title, List<Map<String, Object?>> records) {
print('> $title');
records.forEach(print);
}
更多关于Flutter数据同步插件synchroflite的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter数据同步插件synchroflite的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是一个关于如何使用Flutter数据同步插件synchroflite
的示例代码。synchroflite
是一个用于Flutter的SQLite数据库同步插件,可以帮助你在多个设备之间同步SQLite数据库。
首先,确保你已经在pubspec.yaml
文件中添加了synchroflite
依赖:
dependencies:
flutter:
sdk: flutter
synchroflite: ^最新版本号 # 请替换为当前最新版本号
然后,运行flutter pub get
来获取依赖。
接下来,我们将展示如何使用synchroflite
来同步SQLite数据库。这个示例将包括初始化数据库、配置同步服务器、以及执行数据同步的基本步骤。
1. 初始化数据库
首先,我们需要初始化SQLite数据库并创建一个表:
import 'package:flutter/material.dart';
import 'package:synchroflite/synchroflite.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Synchroflite Example'),
),
body: SynchrofliteExample(),
),
);
}
}
class SynchrofliteExample extends StatefulWidget {
@override
_SynchrofliteExampleState createState() => _SynchrofliteExampleState();
}
class _SynchrofliteExampleState extends State<SynchrofliteExample> {
late SynchrofliteDatabaseHelper _dbHelper;
@override
void initState() {
super.initState();
_initializeDatabase();
}
Future<void> _initializeDatabase() async {
_dbHelper = SynchrofliteDatabaseHelper(
databaseName: 'example.db',
tables: [
SynchrofliteTable(
tableName: 'users',
columns: [
SynchrofliteColumn(name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true),
SynchrofliteColumn(name: 'name', type: 'TEXT'),
SynchrofliteColumn(name: 'email', type: 'TEXT'),
],
),
],
);
// Create the database
await _dbHelper.openDatabase();
// Create the sync configuration (this would typically be done once)
await _dbHelper.createSyncConfig(
syncUrl: 'https://your-sync-server-url.com/sync', // Replace with your sync server URL
tables: ['users'],
);
}
@override
Widget build(BuildContext context) {
return Center(
child: Text('Database Initialized'),
);
}
}
2. 插入数据
接下来,我们插入一些数据到数据库中:
Future<void> _insertData() async {
final db = await _dbHelper.database;
await db.insert(
'users',
{
'name': 'John Doe',
'email': 'john.doe@example.com',
},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
你可以在按钮点击事件中调用_insertData()
方法:
ElevatedButton(
onPressed: () async {
await _insertData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Data Inserted')));
},
child: Text('Insert Data'),
),
3. 执行同步
最后,我们可以执行数据同步:
Future<void> _syncData() async {
await _dbHelper.syncData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Data Synced')));
}
同样地,你可以在另一个按钮点击事件中调用_syncData()
方法:
ElevatedButton(
onPressed: () async {
await _syncData();
},
child: Text('Sync Data'),
),
完整示例
将上述代码整合到一个完整的示例中:
import 'package:flutter/material.dart';
import 'package:synchroflite/synchroflite.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Synchroflite Example'),
),
body: SynchrofliteExample(),
),
);
}
}
class SynchrofliteExample extends StatefulWidget {
@override
_SynchrofliteExampleState createState() => _SynchrofliteExampleState();
}
class _SynchrofliteExampleState extends State<SynchrofliteExample> {
late SynchrofliteDatabaseHelper _dbHelper;
@override
void initState() {
super.initState();
_initializeDatabase();
}
Future<void> _initializeDatabase() async {
_dbHelper = SynchrofliteDatabaseHelper(
databaseName: 'example.db',
tables: [
SynchrofliteTable(
tableName: 'users',
columns: [
SynchrofliteColumn(name: 'id', type: 'INTEGER', primaryKey: true, autoIncrement: true),
SynchrofliteColumn(name: 'name', type: 'TEXT'),
SynchrofliteColumn(name: 'email', type: 'TEXT'),
],
),
],
);
await _dbHelper.openDatabase();
await _dbHelper.createSyncConfig(
syncUrl: 'https://your-sync-server-url.com/sync', // Replace with your sync server URL
tables: ['users'],
);
}
Future<void> _insertData() async {
final db = await _dbHelper.database;
await db.insert(
'users',
{
'name': 'John Doe',
'email': 'john.doe@example.com',
},
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<void> _syncData() async {
await _dbHelper.syncData();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
await _insertData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Data Inserted')));
},
child: Text('Insert Data'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () async {
await _syncData();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Data Synced')));
},
child: Text('Sync Data'),
),
],
);
}
}
请注意,上述代码示例假设你已经有一个同步服务器在运行,并且URL https://your-sync-server-url.com/sync
是有效的。你需要根据你的实际情况替换这个URL。此外,synchroflite
插件的具体API可能会随着版本的更新而有所变化,因此请参考最新的官方文档以确保兼容性。