面试题答案
一键面试面临的挑战
- 平台差异
- 文件路径不同:iOS和Android获取数据库文件路径方式不同。在iOS上,数据库文件通常存储在应用的沙盒目录下,而Android则有特定的内部存储和外部存储路径可供选择。
- 权限管理差异:Android对文件读写权限要求较为严格,需要在AndroidManifest.xml中声明相应权限,如读写外部存储权限。iOS则相对宽松,但也有其自身的文件访问规则。
- 并发操作
- 资源竞争:多个线程或异步任务同时访问和修改数据库时,可能导致数据不一致。例如,一个任务正在读取数据,另一个任务同时进行写入操作,可能会读取到未完成修改的数据。
- 死锁问题:当多个线程相互等待对方释放资源时,可能会出现死锁。比如,线程A持有锁1并等待锁2,而线程B持有锁2并等待锁1。
设计思路
- 平台适配层
- 创建一个抽象的数据库路径获取接口,针对iOS和Android分别实现具体的路径获取方法。例如,使用
path_provider
插件,在iOS实现中通过getApplicationDocumentsDirectory
获取沙盒路径,在Android实现中通过getExternalStorageDirectory
(如果需要外部存储)或getApplicationDocumentsDirectory
获取相应路径。 - 对于权限管理,在Android端利用
permission_handler
插件,在需要权限时进行动态申请;iOS端通过配置Info.plist
文件确保应用有相应权限。
- 创建一个抽象的数据库路径获取接口,针对iOS和Android分别实现具体的路径获取方法。例如,使用
- 并发控制层
- 使用单例模式管理数据库连接。这样可以确保整个应用中只有一个数据库连接实例,避免多个连接同时操作数据库引发的问题。
- 采用锁机制,如
Lock
类,在进行数据库读写操作时加锁,确保同一时间只有一个任务能访问数据库。对于读操作,可以允许多个任务同时进行,但写操作必须独占数据库连接。
关键实现要点
- 数据库连接管理
class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper._internal(); late Database _database; factory DatabaseHelper() { return _instance; } DatabaseHelper._internal(); Future<Database> get database async { if (_database!= null) { return _database; } _database = await openDatabase( join(await getDatabasesPath(), 'app_database.db'), onCreate: (db, version) { return db.execute( 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)', ); }, version: 1, ); return _database; } }
- 并发操作锁控制
import 'dart:async'; import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import 'dart:async'; import 'dart:io'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; class DatabaseHelper { static final DatabaseHelper _instance = DatabaseHelper._internal(); late Database _database; final Lock _lock = Lock(); factory DatabaseHelper() { return _instance; } DatabaseHelper._internal(); Future<Database> get database async { if (_database!= null) { return _database; } _database = await openDatabase( join(await getDatabasesPath(), 'app_database.db'), onCreate: (db, version) { return db.execute( 'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)', ); }, version: 1, ); return _database; } Future<void> insertUser(Map<String, dynamic> user) async { await _lock.synchronized(() async { final db = await database; await db.insert('users', user); }); } Future<List<Map<String, dynamic>>> queryUsers() async { return await _lock.synchronized(() async { final db = await database; return await db.query('users'); }); } }
- 平台特定代码处理
- Android权限申请:
import 'package:permission_handler/permission_handler.dart'; Future<void> requestPermissions() async { final status = await Permission.storage.request(); if (status.isDenied) { // 处理权限被拒绝情况 } }
- iOS配置
Info.plist
:在Info.plist
中添加相应权限配置,如访问文件权限相关配置。