MST

星途 面试题库

面试题:Flutter SQLite数据库事务管理与并发控制

在一个Flutter应用中,存在多个页面同时对SQLite数据库进行操作,涉及到增删改查。请详细说明如何使用事务来确保数据的一致性和完整性,以及如何处理并发操作可能导致的冲突。给出完整的事务处理和并发控制的代码架构示例,并解释其中关键步骤的作用。
42.9万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试
  1. 使用事务确保数据一致性和完整性

    • 在Flutter中使用sqflite库来操作SQLite数据库。事务可以将多个数据库操作作为一个原子单元执行,要么全部成功,要么全部失败。
    • 关键步骤及作用
      • 开启事务:通过database.transaction方法开启一个事务。这一步骤的作用是告诉数据库,接下来的操作将作为一个整体进行处理,如果其中任何一个操作失败,整个事务将回滚。
      • 执行操作:在事务闭包内执行增删改查等数据库操作。这些操作会暂时存储在事务中,不会立即提交到数据库。
      • 提交事务:如果所有操作都成功,通过transaction.commit()方法提交事务,将所有操作永久保存到数据库。
      • 回滚事务:如果在事务执行过程中任何操作抛出异常,事务会自动回滚,撤销所有已执行的操作,确保数据库状态不变。
  2. 处理并发操作导致的冲突

    • 使用同步机制:在Flutter中,可以使用dart:async库中的Lock来同步对数据库的访问。Lock可以确保同一时间只有一个页面的操作能够进入事务,避免并发冲突。
    • 关键步骤及作用
      • 创建Lock实例:在应用的合适位置(比如数据库操作的管理类中)创建一个Lock实例。
      • 获取锁:在进行数据库事务操作前,使用await lock.lock()获取锁。这一步确保当前只有一个页面能够进行数据库操作,其他页面需要等待锁的释放。
      • 释放锁:在事务完成(无论是成功提交还是回滚)后,使用lock.unlock()释放锁,让其他页面可以获取锁并进行操作。
  3. 代码架构示例

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'package:async/async.dart';

class DatabaseHelper {
  static final DatabaseHelper instance = DatabaseHelper._init();
  static Database? _database;
  final Lock lock = Lock();

  DatabaseHelper._init();

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('my_database.db');
    return _database!;
  }

  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);
    return await openDatabase(
      path,
      version: 1,
      onCreate: (Database db, int version) async {
        await db.execute('''
          CREATE TABLE users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            age INTEGER NOT NULL
          )
        ''');
      },
    );
  }

  Future<void> insertUser(Map<String, dynamic> user) async {
    await lock.lock();
    try {
      final db = await instance.database;
      await db.transaction((txn) async {
        await txn.insert('users', user);
      });
    } finally {
      lock.unlock();
    }
  }

  Future<void> updateUser(Map<String, dynamic> user, int id) async {
    await lock.lock();
    try {
      final db = await instance.database;
      await db.transaction((txn) async {
        await txn.update(
          'users',
          user,
          where: 'id =?',
          whereArgs: [id],
        );
      });
    } finally {
      lock.unlock();
    }
  }

  Future<void> deleteUser(int id) async {
    await lock.lock();
    try {
      final db = await instance.database;
      await db.transaction((txn) async {
        await txn.delete(
          'users',
          where: 'id =?',
          whereArgs: [id],
        );
      });
    } finally {
      lock.unlock();
    }
  }

  Future<List<Map<String, dynamic>>> queryAllUsers() async {
    await lock.lock();
    try {
      final db = await instance.database;
      return await db.query('users');
    } finally {
      lock.unlock();
    }
  }
}

在上述代码中:

  • DatabaseHelper类负责管理数据库连接和操作。
  • lock实例用于同步并发操作。
  • insertUserupdateUserdeleteUserqueryAllUsers方法展示了如何在获取锁后进行数据库事务操作,确保数据的一致性和完整性,同时处理并发冲突。