You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter的SQLite数据库中实现用户专属数据隔离?

解决方案:通过用户ID字段实现SQLite数据隔离

要实现同一设备不同用户的数据隔离,核心是给每条数据绑定当前登录用户的Firebase UID,所有数据库操作都基于这个UID做过滤。以下是具体修改步骤:

1. 更新数据模型与表字段

首先在你的CalcResult模型中添加userId字段,同时更新对应的字段常量和序列化方法:

// 修改CalcResult模型
class CalcResult {
  final int? id;
  final String userId; // 新增用户ID字段
  // 保留原有其他字段

  CalcResult({
    this.id,
    required this.userId,
    // 原有字段的构造参数
  });

  // 更新copy方法,包含userId
  CalcResult copy({
    int? id,
    String? userId,
    // 原有字段的copy参数
  }) {
    return CalcResult(
      id: id ?? this.id,
      userId: userId ?? this.userId,
      // 原有字段的赋值
    );
  }

  // 更新toJson方法
  Map<String, dynamic> toJson() => {
        CalcResultFields.id: id,
        CalcResultFields.userId: userId,
        // 原有字段的序列化
      };

  // 更新fromJson方法
  static CalcResult fromJson(Map<String, dynamic> json) => CalcResult(
        id: json[CalcResultFields.id] as int?,
        userId: json[CalcResultFields.userId] as String,
        // 原有字段的反序列化
      );
}

// 更新字段常量类
class CalcResultFields {
  static final List<String> calcValues = [id, userId, /* 原有字段 */];
  static const String id = '_id';
  static const String userId = 'user_id'; // 新增字段常量
  // 原有字段常量
}

2. 更新数据库表结构(创建与升级)

修改数据库的_create和_update方法,添加user_id列:

// 修改_create方法,创建表时加入user_id字段
Future<void> _create(Database db) async {
  await db.execute('''
    CREATE TABLE $calcResults (
      ${CalcResultFields.id} INTEGER PRIMARY KEY AUTOINCREMENT,
      ${CalcResultFields.userId} TEXT NOT NULL, -- 新增用户ID列,添加非空约束
      -- 原有字段定义
    )
  ''');
}

// 修改_update方法,处理表结构升级(版本从11升至12)
Future<void> _update(Database db, int oldVersion, int newVersion) async {
  if (oldVersion < 12) {
    // 给现有表添加user_id列,默认空字符串(可根据实际需求调整)
    await db.execute('ALTER TABLE $calcResults ADD COLUMN ${CalcResultFields.userId} TEXT NOT NULL DEFAULT ""');
    // 可选:给存量数据补全用户ID(如果是已上线应用,需谨慎处理)
  }
  // 原有升级逻辑
}

// 更新数据库版本号
Future<Database> _initDB(String filePath) async {
  final path = await getDatabasesPath();
  final dbPath = join(path, filePath);
  return await openDatabase(dbPath,
      version: 12, // 版本号+1
      onCreate: _create,
      onUpgrade: _update);
}

3. 创建数据时自动绑定用户ID

在创建数据的方法中,获取当前登录用户的Firebase UID并注入到数据对象:

import 'package:firebase_auth/firebase_auth.dart';

Future<CalcResult> create(CalcResult calcResult) async {
  final db = await instance.database;
  final currentUser = FirebaseAuth.instance.currentUser;
  if (currentUser == null) {
    throw Exception('用户未登录');
  }
  // 将用户ID绑定到待创建的数据
  final userBoundResult = calcResult.copy(userId: currentUser.uid);
  final id = await db.insert(calcResults, userBoundResult.toJson());
  return userBoundResult.copy(id: id);
}

4. 读取数据时过滤当前用户ID

修改读取单条和所有数据的方法,添加用户ID的过滤条件:

读取单条数据:

Future<CalcResult> readNote(int id) async {
  final db = await instance.database;
  final currentUser = FirebaseAuth.instance.currentUser;
  if (currentUser == null) {
    throw Exception('用户未登录');
  }

  final maps = await db.query(
    calcResults,
    columns: CalcResultFields.calcValues,
    where: '${CalcResultFields.id} = ? AND ${CalcResultFields.userId} = ?',
    whereArgs: [id, currentUser.uid],
  );

  if (maps.isNotEmpty) {
    return CalcResult.fromJson(maps.first);
  } else {
    throw Exception('ID $id不存在或不属于当前用户');
  }
}

读取所有数据:

Future<List<CalcResult>> readAllNotes() async {
  final db = await instance.database;
  final currentUser = FirebaseAuth.instance.currentUser;
  if (currentUser == null) {
    throw Exception('用户未登录');
  }

  final orderBy =
      '${CalcResultFields.toDate} DESC, ${CalcResultFields.toTime} DESC';
  final result = await db.query(
    calcResults,
    orderBy: orderBy,
    where: '${CalcResultFields.userId} = ?',
    whereArgs: [currentUser.uid],
  );
  return result.map((json) => CalcResult.fromJson(json)).toList();
}

可选优化:用户登出时重置数据库实例

在用户登出后重置数据库实例,避免后续操作出现异常:

// 在DatabaseClientCalculations类中添加重置方法
Future<void> resetDatabase() async {
  if (_database != null) {
    await _database!.close();
    _database = null;
  }
}

// 登出时调用
await FirebaseAuth.instance.signOut();
await DatabaseClientCalculations.instance.resetDatabase();

修改完成后,每条数据都会与对应的用户UID绑定,不同用户登录后仅能访问自己的数据,实现了数据隔离。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 22:55:18