Skip to content

移动端与服务端数据库、Redis 缓存体系总览 ​

回到总览:后台 / API / 数据层
相关模块:缓存更新策略与常见坑:穿透、击穿、雪崩与一致性 · 状态持久化、内存恢复与分层恢复策略

一句话定义 ​

数据库与缓存体系是指在移动端(SQLite / Room / Hive / MMKV)与服务端(MySQL / PostgreSQL / Redis / MongoDB)架构中,根据数据的结构化程度、读写吞吐要求以及持久化诉求,选择最适存储引擎并进行多级缓存设计的技术体系。

代码索引 ​

对应 Lab:database-cache-simulation

  • labs/shared/backend-data/database-cache-demo/ — Room 数据库 WAL 模式优化与 MMKV 键值对性能测试

为什么需要 ​

  • 为什么移动端本地存储大批量数据时,使用 SQLite (Room) 远比将 JSON 序列化后存入 SharedPreferences / 文件好得多?
    • 一句话答:SharedPreferences 每次修改都需要将整个 XML 全量读写磁盘;而 SQLite 拥有 B+ 树索引与 WAL(预写日志)机制,支持局部增删改查与事务操作,数据量越大性能差距越呈数量级放大。
  • 为什么 10 年 Android 工程师必须理解后端 Redis 缓存与移动端本地缓存的异同?
    • 一句话答:两者本质都是“以空间换时间”的缓存层;服务端 Redis 解决的是高并发 QPS 压垮关系型数据库的问题,移动端本地缓存解决的是弱网无网下的离线可读与首帧渲染体验。

底层机制 ​

1. 移动端与服务端存储选型全景矩阵 ​

text
                           移动端/客户端 (Client)
  ┌───────────────────────────┬───────────────────────────┐
  │ 键值/小配置 (KV/Prefs)    │ 结构化数据 (Relational)   │
  │  - MMKV (mmap 内存映射)   │  - SQLite / Room (Android)│
  │  - SharedPreferences (旧) │  - Hive / Isar (Flutter)  │
  └───────────────────────────┴───────────────────────────┘
                                   │
                                   ▼ (HTTP / API 网络交互)
                           服务端/后台 (Server)
  ┌───────────────────────────┬───────────────────────────┐
  │ 高速内存缓存 (In-Memory)  │ 持久化数据库 (DB)         │
  │  - Redis (单线程/IO多路复用)│  - MySQL / PostgreSQL     │
  │  - Memcached              │  - MongoDB (文档型 NoSQL) │
  └───────────────────────────┴───────────────────────────┘

典型存储引擎对比表 ​

存储引擎存储类型数据位置核心优势缺点/局限
MMKVKey-Value内存映射 (mmap)极其高速,崩溃数据不丢失,多进程安全不适合复杂 SQL 条件查询
Room (SQLite)关系型 (RDBMS)磁盘文件 (.db)支持 SQL 复杂查询、事务、ORM 映射大批量并发写入需要开启 WAL
RedisKey-Value (多数据结构)内存 + 磁盘 RDB/AOFQPS 达十万级,支持 List/Hash/ZSet内存昂贵,数据非 100% 强一致
MySQL关系型 (RDBMS)磁盘 (B+ 树)强 ACID 事务支持,数据高度结构化无法承受数十万级高并发直读

2. SQLite WAL (Write-Ahead Logging) 预写日志原理 ​

对应 Lab:database-cache-simulation

传统 SQLite 写入会锁住整个数据库(读写互斥);开启 WAL 模式后:

  1. 写操作:不直接修改原数据库文件,而是顺序追加写入到 .db-wal 日志文件中。
  2. 读操作:先查 WAL 日志,再查原数据库文件。
  3. 读写并发:读写不再互相阻塞,大幅提升了移动端数据库的并发性能。

Android / Flutter / Web / Backend 对照 ​

维度Android 原生Flutter 框架服务端 (Java/Node)
键值存储MMKV / DataStoreshared_preferences / hiveRedis
数据库Room (SQLite)sqflite / isarSpring Data JPA / MyBatis (MySQL)
缓存淘汰LruCache (内存)ImageCache (内存)Redis allkeys-lru / Caffeine

常见场景与代码优化 ​

1. Room 数据库开启 WAL 模式与事务批量写入 ​

java
// 开启 WAL 模式提升并发读写性能
Room.databaseBuilder(context, AppDatabase.class, "app_db")
    .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING)
    .build();

// 批量插入必须使用事务 (@Transaction),性能提升百倍!
@Transaction
public void insertUserList(List<User> users) {
    userDao.insertAll(users);
}

常见误配、事故后果与排障 ​

1. 事故:在主线程直接调用 Room 数据库读写引发 ANR ​

  • 误配原因:未在 Room 构造时禁止主线程读写,直接在 UI 线程执行 userDao.getAllUsers()。
  • 后果:SQLite 磁盘 I/O 阻塞主线程,抛出 Cannot access database on the main thread 或触发 ANR。
  • 排障与修法:Room 配合 Kotlin 协程 suspend 函数,自动将底层 I/O 派发到 Dispatchers.IO 执行。

与相近概念对比 ​

数据结构Redis 对应类型典型应用场景
String字符串 / 字节流缓存 JSON 对象、Token 令牌、计数器
Hash哈希表 (Map)存储用户信息结构(可单独修改某个 Field)
ZSet有序集合 (Sorted Set)实时排行榜(根据 Score 自动排序)

对应实验 ​

Lab说明源码
database-cache-simulationSQLite WAL 读写并发 + 内存/磁盘/远端三级缓存DatabaseCacheSimulation.java
  • labs/shared/backend-data/database-cache-demo/ — Room 数据库 WAL 模式优化与 MMKV 键值对性能测试

复习检查题 ​

  1. 为什么 Android 移动端使用 MMKV 替代 SharedPreferences 性能会有质的飞跃?

    答:SharedPreferences 写入时采用全量 XML 序列化并写入磁盘,频繁修改开销极大;而 MMKV 基于 mmap(内存映射) 机制,将文件直接映射到进程的虚拟内存空间,读写内存就等于读写磁盘。同时 MMKV 使用 Protocol Buffers 增量序列化,避免了全量重新写入,即使应用发生 Crash 崩溃,操作系统内核也会保证内存映射的数据安全落盘。

  2. SQLite 开启 WAL (Write-Ahead Logging) 模式有什么好处?

    答:传统 SQLite 在写入时会锁定整个数据库文件,导致读操作和写操作互相阻塞。开启 WAL 模式后,所有的写操作都会改为顺序追加写入独立的 .db-wal 日志文件中,原数据库文件保持不变。这实现了**“读不阻塞写,写也不阻塞读”**,极大地提升了并发读写性能。

速记 ​

  • KV 首选 MMKV:基于 mmap 内存映射,崩溃不丢数据,读写性能远超 SP。
  • SQLite 开 WAL:开启 WAL 预写日志,读写互不阻塞,大批量插入必加事务。
  • 后端 Redis 缓存:QPS 十万级高并发,内存存储 + 异步持久化。

站点构建时间:2026/8/24 23:43:17