面试题答案
一键面试使用锁机制确保数据一致性
- 理论依据:
- 在Flutter中,锁机制可以防止多个异步任务同时访问和修改共享资源(这里指数据存储)。通过锁定资源,当一个任务获取到锁时,其他任务必须等待锁释放后才能访问该资源,从而避免了数据竞争和不一致问题。
- 代码示例:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
// 创建一个锁对象
final Lock lock = Lock();
Future<void> performNetworkDownloadAndStore() async {
await lock.synchronized(() async {
// 模拟网络数据下载
await Future.delayed(const Duration(seconds: 2));
String data = "Downloaded data";
// 存储到本地数据库
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'test.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)');
});
await database.insert('data', {'value': data});
});
}
Future<void> performLocalDataUpdate() async {
await lock.synchronized(() async {
// 模拟本地数据更新
await Future.delayed(const Duration(seconds: 1));
String newData = "Updated local data";
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'test.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)');
});
await database.update('data', {'value': newData}, where: 'id = 1');
});
}
在上述代码中,Lock
类来自dart:io
库,synchronized
方法确保传入的异步函数在同一时间只有一个能执行,从而保证了数据存储的一致性。
使用事务处理确保数据一致性
- 理论依据:
- 事务是一个不可分割的操作序列,要么全部成功执行,要么全部失败回滚。在数据存储中,事务可以保证多个相关的数据操作作为一个整体,要么都成功保存到数据库,要么都不保存,这样可以确保数据的一致性。例如,在更新多条相关记录时,如果其中一条更新失败,事务回滚可以保证其他记录不会被错误地更新。
- 代码示例:
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
Future<void> performComplexDataOperation() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'test.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)');
});
await database.transaction((txn) async {
// 模拟网络数据下载存储
await Future.delayed(const Duration(seconds: 2));
String networkData = "Downloaded data";
await txn.insert('data', {'value': networkData});
// 模拟本地数据更新
await Future.delayed(const Duration(seconds: 1));
String newLocalData = "Updated local data";
await txn.update('data', {'value': newLocalData}, where: 'id = 1');
});
}
在这段代码中,database.transaction
方法开启一个事务,在事务块内的所有数据库操作要么全部成功提交,要么在任何一个操作失败时全部回滚,从而保证了数据一致性。
其他策略
- 队列处理:
- 理论依据:将所有的数据存储操作放入一个队列中,然后按顺序依次处理。这样可以避免多个任务同时操作数据存储,保证数据一致性。例如,先进入队列的网络下载存储任务先执行,完成后再执行本地数据更新存储任务。
- 代码示例:
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
final Queue<Future<void>> operationQueue = Queue();
Future<void> addOperationToQueue(Future<void> operation) {
Completer<void> completer = Completer();
operationQueue.add(operation.then((_) {
completer.complete();
if (operationQueue.isNotEmpty) {
addOperationToQueue(operationQueue.removeFirst());
}
}).catchError((error) {
completer.completeError(error);
}));
if (operationQueue.length == 1) {
addOperationToQueue(operationQueue.removeFirst());
}
return completer.future;
}
Future<void> performNetworkDownloadAndStore() async {
await addOperationToQueue(() async {
// 模拟网络数据下载
await Future.delayed(const Duration(seconds: 2));
String data = "Downloaded data";
// 存储到本地数据库
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'test.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)');
});
await database.insert('data', {'value': data});
});
}
Future<void> performLocalDataUpdate() async {
await addOperationToQueue(() async {
// 模拟本地数据更新
await Future.delayed(const Duration(seconds: 1));
String newData = "Updated local data";
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'test.db');
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)');
});
await database.update('data', {'value': newData}, where: 'id = 1');
});
}
在这个示例中,addOperationToQueue
方法将异步操作添加到队列中,并按顺序依次执行,保证了数据存储的一致性。