Appearance
源码:labs/java/backend-data/database-cache-simulation/src/DatabaseCacheSimulation.java
- 原始路径:
labs/java/backend-data/database-cache-simulation/src/DatabaseCacheSimulation.java - 类型:
java
java
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 移动端数据库与缓存仿真:SQLite WAL vs 传统锁 + 多级缓存。
*
* 对应 docs 06-backend-data/02-database-cache-overview.md:
* 1. 传统 SQLite:写入锁整个库 → 写时读被阻塞(读不阻塞写?不,传统是互斥)
* 2. WAL 模式:写进独立 -wal 日志,原库只读 → 读不阻塞写、写不阻塞读
* 3. 多级缓存:内存 → 磁盘(SQLite) → 远端 API 的分层读取与命中统计
*
* 纯 Java CLI(无外部依赖)。
* 运行:javac -d out src/DatabaseCacheSimulation.java && java -cp out DatabaseCacheSimulation
*/
public class DatabaseCacheSimulation {
// 模拟"数据库文件":WAL 模式下写入先进 wal,读直接读原库
static final ConcurrentHashMap<String, String> DB_FILE = new ConcurrentHashMap<>();
static final ConcurrentHashMap<String, String> WAL = new ConcurrentHashMap<>();
static boolean walEnabled = true;
public static void main(String[] args) {
System.out.println("========== 1. 传统锁模式 vs WAL 模式:读写并发 ==========");
// 传统模式:写锁整库,读必须等写完成(串行)
System.out.println(" [传统模式] 写锁整库 → 读等待写完成 → 读写互斥,并发低");
// WAL 模式:写进 -wal,读直接读原库
System.out.println(" [WAL 模式] 写追加进 -wal 日志,读读原库 → 读写并行,并发高");
walEnabled = true;
System.out.println(" 本 demo 用 WAL 语义:write() 先写 WAL(立即返回),read() 读 DB_FILE 不受影响");
System.out.println();
System.out.println("========== 2. WAL 写入流程 ==========");
write("user:1", "Alice_v2");
System.out.println(" write: 追加到 WAL {user:1=Alice_v2},原库尚未合并 → 写入方无需等待读方");
System.out.println(" 并发读 user:1 -> " + read("user:1") + "(读的是原库旧值或合并后新值,读不阻塞)");
System.out.println();
System.out.println("========== 3. 多级缓存分层读取(内存 → 磁盘 → 远端)==========");
// 分层:内存缓存 > SQLite(磁盘) > 远端 API
ConcurrentHashMap<String, String> memoryCache = new ConcurrentHashMap<>();
ConcurrentHashMap<String, String> diskDb = new ConcurrentHashMap<>();
AtomicInteger remoteHits = new AtomicInteger();
String key = "feed:10086";
for (int i = 0; i < 5; i++) {
String v = layeredGet(key, memoryCache, diskDb, remoteHits);
}
System.out.println(" 5 次读 feed:10086 → 远端(DB/API) 回源次数 = " + remoteHits.get()
+ "(首次回源后内存/磁盘命中,后续 0 回源)");
System.out.println();
System.out.println("========== 4. 结论 ==========");
System.out.println(" · SQLite 开 WAL:读不阻塞写、写不阻塞读,大批量写入配合事务");
System.out.println(" · 移动端分层缓存:内存(最快) → 磁盘(SQLite) → 远端(兜底),命中率优先内存");
}
/** WAL 语义写入:先进 WAL(模拟顺序追加日志) */
static void write(String key, String value) {
WAL.put(key, value); // 顺序追加,无锁
DB_FILE.put(key, value); // 简化:立即合并(真实是 checkpoint 时机合并)
}
/** WAL 语义读取:直接读原库(不阻塞) */
static String read(String key) {
return DB_FILE.get(key);
}
/** 分层读取:内存 → 磁盘 → 远端 */
static String layeredGet(String key,
ConcurrentHashMap<String, String> memory,
ConcurrentHashMap<String, String> disk,
AtomicInteger remoteHits) {
String v = memory.get(key);
if (v != null) return v;
v = disk.get(key);
if (v != null) {
memory.put(key, v); // 磁盘命中 → 提升到内存
return v;
}
// 远端回源(真实场景是网络请求)
remoteHits.incrementAndGet();
v = "remote_data_for_" + key;
disk.put(key, v);
memory.put(key, v);
return v;
}
}