跳转至

Hive 数据库使用教程

Hive 是高性能 NoSQL 键值对数据库,支持加密和 Web,适合离线缓存和复杂对象存储。


一、简介

1.1 什么是 Hive?

Hive 是轻量级 NoSQL 数据库: - 高性能:纯 Dart 实现,无需桥接 - 键值对存储:类似 JSON 的文档数据库 - 类型安全:支持 TypeAdapter 序列化 - 加密支持:可选 AES 加密 - Web 支持:可在 Web 端使用

1.2 适用场景

  • 离线数据缓存
  • 复杂对象存储
  • 需要加密的敏感数据
  • 离线优先应用
  • 快速原型开发

1.3 官方资源

资源 链接
Pub 页面 https://pub.dev/packages/hive
Flutter 封装 https://pub.dev/packages/hive_flutter
官方文档 https://docs.hivedb.dev/
GitHub https://github.com/hivedb/hive

二、安装配置

2.1 添加依赖

# pubspec.yaml
dependencies:
  hive: ^2.2.3
  hive_flutter: ^1.1.0

dev_dependencies:
  hive_generator: ^2.0.1
  build_runner: ^2.4.7

2.2 安装命令

flutter pub get

三、基础用法

3.1 初始化

import 'package:hive_flutter/hive_flutter.dart';

void main() async {
  await Hive.initFlutter();
  runApp(MyApp());
}

3.2 打开 Box

// 打开普通 Box
var box = await Hive.openBox('myBox');

// 打开加密 Box
var encryptedBox = await Hive.openBox(
  'secureBox',
  encryptionCipher: HiveAesCipher(key),
);

3.3 写入数据

// 存储任何类型
box.put('name', 'Luke');
box.put('age', 25);
box.put('isActive', true);
box.put('scores', [100, 90, 85]);
box.put('metadata', {'theme': 'dark', 'lang': 'zh'});

// 存储日期
box.put('createdAt', DateTime.now());

3.4 读取数据

// 读取值
String name = box.get('name', defaultValue: 'default');
int age = box.get('age', defaultValue: 0);
bool isActive = box.get('isActive', defaultValue: false);

// 读取列表
List scores = box.get('scores', defaultValue: []);

// 读取 Map
Map metadata = box.get('metadata', defaultValue: {});

3.5 删除数据

// 删除单个
box.delete('name');

// 删除多个
box.deleteAll(['name', 'age']);

// 清空 Box
box.clear();

四、类型适配器(TypeAdapter)

4.1 简单模型

// 定义模型
@HiveType(typeId: 0)
class User {
  @HiveField(0)
  String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  String? email;

  User({required this.name, required this.age, this.email});
}

4.2 生成适配器

dart run build_runner build

生成 user.g.dart

@HiveType(typeId: 0)
class User extends HiveObject {
  @HiveField(0)
  String name;

  @HiveField(1)
  int age;

  @HiveField(2)
  String? email;

  User({required this.name, required this.age, this.email});
}

// 自动生成的适配器
class UserAdapter extends TypeAdapter<User> {
  @override
  final int typeId = 0;

  @override
  User read(BinaryReader reader) {
    final numOfFields = reader.readByte();
    final fields = <int, dynamic>{
      for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
    };
    return User(
      name: fields[0] as String,
      age: fields[1] as int,
      email: fields[2] as String?,
    );
  }

  @override
  void write(BinaryWriter writer, User obj) {
    writer
      ..writeByte(3)
      ..writeByte(0)
      ..write(obj.name)
      ..writeByte(1)
      ..write(obj.age)
      ..writeByte(2)
      ..write(obj.email);
  }

  @override
  int get hashCode => typeId.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is UserAdapter &&
          runtimeType == other.runtimeType &&
          typeId == other.typeId;
}

4.3 注册适配器

void main() async {
  await Hive.initFlutter();

  // 注册适配器
  Hive.registerAdapter(UserAdapter());

  // 打开 Box(指定类型)
  var userBox = await Hive.openBox<User>('users');

  runApp(MyApp());
}

4.4 使用模型

// 存储 User 对象
var user = User(name: 'Luke', age: 25, email: 'luke@example.com');
await userBox.put('user1', user);

// 读取 User 对象
User? user = userBox.get('user1');
print(user?.name);  // Luke

// 获取所有用户
List<User> allUsers = userBox.values.toList();

五、进阶用法

5.1 Box 监听

// 监听变化
box.listenable().addListener(() {
  print('Box 发生了变化');
});

// 或使用流
box.watch().listen((event) {
  print('Key: ${event.key}, Value: ${event.value}');
});

5.2 加密 Box

import 'dart:convert';
import 'dart:typed_data';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter/foundation.dart';

Future<void> initHive() async {
  await Hive.initFlutter();

  // 生成加密密钥
  final key = Hive.generateSecureKey();
  final cipher = HiveAesCipher(key);

  // 保存密钥(安全方式存储)
  // 实际应用中建议使用 flutter_secure_storage
  final secureBox = await Hive.openBox('secure_box');
  await secureBox.put('key', base64Encode(key));

  // 打开加密 Box
  final encryptedBox = await Hive.openBox(
    'encrypted_data',
    encryptionCipher: cipher,
  );
}

5.3 Lazy Box(延迟加载)

// Lazy Box 按需加载,性能更好
var lazyBox = await Hive.openLazyBox('lazyUsers');

// 实际读取时才加载
final user = await lazyBox.get('user1');

// 关闭不再需要的 Lazy Box
await lazyBox.close();

5.4 Box 嵌套

// 打开子 Box
var parentBox = await Hive.openBox('parent');
var childBox = await parentBox.openBox('child');

// 存储
await childBox.put('nested', 'value');

// 读取
final value = await parentBox.get('child.nested');

六、结合 GetX 使用

6.1 创建 Service

// lib/services/hive_service.dart
import 'package:get/get.dart';
import 'package:hive_flutter/hive_flutter.dart';

class HiveService extends GetxService {
  late final Box _settingsBox;
  late final Box _cacheBox;

  Box get settings => _settingsBox;
  Box get cache => _cacheBox;

  Future<HiveService> init() async {
    await Hive.initFlutter();

    // 打开设置 Box
    _settingsBox = await Hive.openBox('settings');

    // 打开缓存 Box
    _cacheBox = await Hive.openBox('cache');

    return this;
  }

  @override
  void onClose() {
    _settingsBox.close();
    _cacheBox.close();
    super.onClose();
  }
}

6.2 初始化

// main.dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Get.putAsync(() => HiveService().init());
  runApp(MyApp());
}

6.3 创建 Controller

// lib/controllers/user_controller.dart
import 'package:get/get.dart';
import '../models/user.dart';
import '../services/hive_service.dart';

class UserController extends GetxController {
  final HiveService _hive = Get.find();
  late final Box<User> _userBox;

  final RxList<User> users = <User>[].obs;
  final Rx<User?> currentUser = Rx<User?>(null);

  @override
  void onInit() {
    super.onInit();
    _initUserBox();
  }

  Future<void> _initUserBox() async {
    // 注册适配器
    if (!Hive.isAdapterRegistered(0)) {
      Hive.registerAdapter(UserAdapter());
    }
    _userBox = await Hive.openBox<User>('users');

    // 监听变化
    _userBox.listenable().addListener(_onUsersChanged);

    // 加载数据
    _loadUsers();
  }

  void _onUsersChanged() {
    users.value = _userBox.values.toList();
  }

  void _loadUsers() {
    users.value = _userBox.values.toList();
    final userId = _hive.settings.get('currentUserId');
    if (userId != null) {
      currentUser.value = _userBox.get(userId);
    }
  }

  Future<void> addUser(User user) async {
    await _userBox.put('user_${user.id}', user);
  }

  Future<void> updateUser(User user) async {
    await _userBox.put('user_${user.id}', user);
  }

  Future<void> deleteUser(int id) async {
    await _userBox.delete('user_$id');
  }

  Future<void> setCurrentUser(User? user) async {
    currentUser.value = user;
    if (user != null) {
      await _hive.settings.put('currentUserId', user.id);
    } else {
      await _hive.settings.remove('currentUserId');
    }
  }
}

七、实战示例:聊天消息缓存

// 定义消息模型
@HiveType(typeId: 1)
class ChatMessage {
  @HiveField(0)
  final String id;

  @HiveField(1)
  final String conversationId;

  @HiveField(2)
  final String content;

  @HiveField(3)
  final int senderId;

  @HiveField(4)
  final DateTime timestamp;

  @HiveField(5)
  final MessageType type;

  @HiveField(6)
  final bool isRead;

  ChatMessage({
    required this.id,
    required this.conversationId,
    required this.content,
    required this.senderId,
    required this.timestamp,
    required this.type,
    this.isRead = false,
  });
}

@HiveType(typeId: 2)
enum MessageType {
  @HiveField(0)
  text,
  @HiveField(1)
  image,
  @HiveField(2)
  file,
}

// 消息缓存服务
class MessageCacheService {
  static const String _boxName = 'messages';

  Future<Box<ChatMessage>> _getBox() async {
    if (!Hive.isAdapterRegistered(1)) {
      Hive.registerAdapter(ChatMessageAdapter());
    }
    if (!Hive.isAdapterRegistered(2)) {
      Hive.registerAdapter(MessageTypeAdapter());
    }
    return await Hive.openBox<ChatMessage>(_boxName);
  }

  Future<void> cacheMessages(List<ChatMessage> messages) async {
    final box = await _getBox();
    final Map<String, ChatMessage> entries = {
      for (var msg in messages) 'msg_${msg.id}': msg
    };
    await box.putAll(entries);
  }

  Future<List<ChatMessage>> getMessages(String conversationId) async {
    final box = await _getBox();
    return box.values
        .where((msg) => msg.conversationId == conversationId)
        .toList()
      ..sort((a, b) => a.timestamp.compareTo(b.timestamp));
  }

  Future<ChatMessage?> getLatestMessage(String conversationId) async {
    final messages = await getMessages(conversationId);
    return messages.isEmpty ? null : messages.last;
  }

  Future<void> clearConversation(String conversationId) async {
    final box = await _getBox();
    final keysToDelete = box.keys
        .where((key) => box.get(key)?.conversationId == conversationId)
        .toList();
    await box.deleteAll(keysToDelete);
  }
}

八、常见问题

8.1 适配器冲突

每个模型需要唯一的 typeId

// 用户模型
@HiveType(typeId: 0)
class User { ... }

// 消息模型
@HiveType(typeId: 1)
class Message { ... }

// 确保 typeId 不重复

8.2 代码生成失败

# 清理并重新生成
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs

8.3 Web 端不支持加密

// Web 端使用不同的加密方式
if (kIsWeb) {
  // Web 使用 IndexedDB,无需特殊处理
  box = await Hive.openBox('myBox');
} else {
  // 移动端使用加密
  box = await Hive.openBox(
    'myBox',
    encryptionCipher: HiveAesCipher(key),
  );
}

8.4 Box 已关闭

// 检查 Box 是否打开
if (box.isOpen) {
  // 安全操作
  await box.put('key', 'value');
}

九、性能优化

9.1 使用 Lazy Box

// 大数据量时使用 Lazy Box
var lazyBox = await Hive.openLazyBox('largeData');

// 按需加载
final item = await lazyBox.get('someKey');

9.2 批量写入

// 使用 putAll 批量写入,性能更好
await box.putAll({
  'key1': value1,
  'key2': value2,
  'key3': value3,
});

9.3 适当关闭 Box

// 不用时关闭,释放内存
await box.close();

// 需要时重新打开
box = await Hive.openBox('myBox');

十、总结

Hive 特点:

  • 高性能:纯 Dart 实现
  • 类型安全:TypeAdapter 序列化
  • 加密支持:可选 AES 加密
  • Web 支持:可在 Web 使用
  • 轻量:无需复杂配置

适用场景: - 离线缓存 - 复杂对象 - 需要加密 - 快速原型

不适用场景: - 超大量数据(建议 drift) - 复杂查询(建议 drift/floor)