MST

星途 面试题库

面试题:Flutter SQLite复杂场景下的数据一致性与事务处理

在一个Flutter金融类应用中,涉及到多个表之间的数据交互,如转账操作涉及到两个账户表的余额变动。如何使用SQLite的事务机制来确保数据的一致性,避免出现部分操作成功部分失败导致数据不一致的情况?请详细阐述事务处理的流程,并给出完整的Flutter代码示例,包括错误处理机制。
29.5万 热度难度
前端开发Flutter

知识考点

AI 面试

面试题答案

一键面试

事务处理流程

  1. 开启事务:在进行转账操作前,开启一个SQLite事务。这确保后续的所有数据库操作都在同一个事务上下文内。
  2. 执行操作:在事务内执行多个数据库操作,如更新转账方账户余额(减少金额)和接收方账户余额(增加金额)。
  3. 提交事务:如果所有操作都成功完成,提交事务,这会使所有在事务内的修改永久生效。
  4. 回滚事务:如果在事务执行过程中任何一个操作失败,回滚事务,撤销所有在事务内已经执行的操作,确保数据回到事务开始前的状态。

Flutter代码示例

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

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

  DatabaseHelper._init();

  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('finance.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: _createDB);
  }

  Future<void> _createDB(Database db, int version) async {
    const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
    const textType = 'TEXT NOT NULL';
    const integerType = 'INTEGER NOT NULL';

    await db.execute('''
      CREATE TABLE accounts (
        id $idType,
        accountName $textType,
        balance $integerType
      )
    ''');
  }

  Future<void> transfer(int fromAccountId, int toAccountId, int amount) async {
    final db = await instance.database;

    try {
      await db.transaction((txn) async {
        // 减少转账方余额
        await txn.rawUpdate(
          'UPDATE accounts SET balance = balance -? WHERE id =?',
          [amount, fromAccountId],
        );

        // 增加接收方余额
        await txn.rawUpdate(
          'UPDATE accounts SET balance = balance +? WHERE id =?',
          [amount, toAccountId],
        );
      });
    } catch (e) {
      // 捕获异常并处理,回滚事务
      print('Transaction failed: $e');
      rethrow;
    }
  }
}

使用示例

void main() async {
  final dbHelper = DatabaseHelper.instance;
  await dbHelper.database;

  try {
    await dbHelper.transfer(1, 2, 100);
    print('Transfer successful');
  } catch (e) {
    print('Transfer failed: $e');
  }
}

错误处理机制

  1. try - catch块:在transfer方法中,使用try - catch块来捕获事务执行过程中的任何异常。如果捕获到异常,打印错误信息并重新抛出异常,以便调用者可以进一步处理。
  2. 事务内操作失败:如果在事务内的任何一个rawUpdate操作失败,transaction方法会自动回滚事务,确保数据一致性。调用者在main函数中的try - catch块可以捕获到错误并进行相应处理。