1. 概述
Xodus 是 JetBrains 开源的一款嵌入式数据库。我们可以用它替代传统关系型数据库。使用 Xodus 能获得高性能的事务型键值存储和面向对象的数据模型。这种存储采用仅追加(append-only)机制,最小化随机 I/O 开销,并默认提供快照隔离。
在 Xodus 中,我们拥有快照隔离机制,保证事务内所有读取操作都能获取到整个数据库的一致性快照。 每个提交的事务都会生成一个新的数据库快照(版本),后续事务可以引用该快照。
本教程将全面介绍 Xodus 数据库的核心概念和功能。
2. Xodus 数据处理原理
Xodus 的数据处理流程如下图所示:
这里,Environment 类负责处理日志文件与内存存储间的所有同步操作。EntityStore 类作为环境的封装层,简化了数据操作流程。
3. 环境(Environments)
环境是 Xodus 的底层 API。我们可以将其用作事务型键值存储。下面通过示例仓库演示环境的使用。
3.1. 依赖配置
首先添加 xodus-openAPI 依赖:
<dependency>
<groupId>org.jetbrains.xodus</groupId>
<artifactId>xodus-openAPI</artifactId>
<version>2.0.1</version>
</dependency>
3.2. save() 方法
创建仓库类实现保存逻辑:
public class TaskEnvironmentRepository {
private static final String DB_PATH = "db.myAppData";
private static final String TASK_STORE = "TaskStore";
public void save(String taskId, String taskDescription) {
try (Environment environment = openEnvironmentExclusively()) {
Transaction writeTransaction = environment.beginExclusiveTransaction();
try {
Store taskStore = environment.openStore(TASK_STORE,
StoreConfig.WITHOUT_DUPLICATES, writeTransaction);
ArrayByteIterable id = StringBinding.stringToEntry(taskId);
ArrayByteIterable value = StringBinding.stringToEntry(taskDescription);
taskStore.put(writeTransaction, id, value);
} catch (Exception e) {
writeTransaction.abort();
} finally {
if (!writeTransaction.isFinished()) {
writeTransaction.commit();
}
}
}
}
private Environment openEnvironmentExclusively() {
return Environments.newInstance(DB_PATH);
}
}
✅ 关键点:
- 指定数据库文件路径(自动创建)
- 打开环境并创建独占事务
- 所有事务必须提交或中止
- 数据需转换为 ArrayByteIterable 格式
3.3. findOne() 方法
添加查询方法:
public String findOne(String taskId) {
try (Environment environment = openEnvironmentExclusively()) {
Transaction readonlyTransaction = environment.beginReadonlyTransaction();
try {
Store taskStore = environment.openStore(TASK_STORE,
StoreConfig.WITHOUT_DUPLICATES, readonlyTransaction);
ArrayByteIterable id = StringBinding.stringToEntry(taskId);
ByteIterable result = taskStore.get(readonlyTransaction, id);
return result == null ? null : StringBinding.entryToString(result);
} finally {
readonlyTransaction.abort();
}
}
}
⚠️ 注意:
- 使用只读事务
- 查询后无需提交,直接中止事务
3.4. findAll() 方法
遍历存储需使用游标:
public Map<String, String> findAll() {
try (Environment environment = openEnvironmentExclusively()) {
Transaction readonlyTransaction = environment.beginReadonlyTransaction();
try {
Store taskStore = environment.openStore(TASK_STORE,
StoreConfig.WITHOUT_DUPLICATES, readonlyTransaction);
Map<String, String> result = new HashMap<>();
try (Cursor cursor = taskStore.openCursor(readonlyTransaction)) {
while (cursor.getNext()) {
result.put(StringBinding.entryToString(cursor.getKey()),
StringBinding.entryToString(cursor.getValue()));
}
}
return result;
} finally {
readonlyTransaction.abort();
}
}
}
✅ 最佳实践:
- 处理后必须关闭游标
- 使用只读事务保证一致性
3.5. deleteAll() 方法
实现全量删除:
public void deleteAll() {
try (Environment environment = openEnvironmentExclusively()) {
Transaction exclusiveTransaction = environment.beginExclusiveTransaction();
try {
Store taskStore = environment.openStore(TASK_STORE,
StoreConfig.WITHOUT_DUPLICATES, exclusiveTransaction);
try (Cursor cursor = taskStore.openCursor(exclusiveTransaction)) {
while (cursor.getNext()) {
taskStore.delete(exclusiveTransaction, cursor.getKey());
}
}
} finally {
exclusiveTransaction.commit();
}
}
}
🔧 操作逻辑:
- 使用游标遍历所有键
- 逐个删除并提交事务
4. 实体存储(Entity Stores)
在实体存储层,我们通过带属性和链接的实体访问数据。该 API 提供了更丰富的查询选项和更高级别的抽象。
4.1. 依赖配置
添加 xodus-entity-store 依赖:
<dependency>
<groupId>org.jetbrains.xodus</groupId>
<artifactId>xodus-entity-store</artifactId>
<version>2.0.1</version>
</dependency>
4.2. save() 方法
先创建模型类:
public class TaskEntity {
private final String description;
private final String labels;
public TaskEntity(String description, String labels) {
this.description = description;
this.labels = labels;
}
// getters
}
实现保存逻辑:
public class TaskEntityStoreRepository {
private static final String DB_PATH = "db.myAppData";
private static final String ENTITY_TYPE = "Task";
public EntityId save(TaskEntity taskEntity) {
try (PersistentEntityStore entityStore = openStore()) {
AtomicReference<EntityId> idHolder = new AtomicReference<>();
entityStore.executeInTransaction(txn -> {
final Entity message = txn.newEntity(ENTITY_TYPE);
message.setProperty("description", taskEntity.getDescription());
message.setProperty("labels", taskEntity.getLabels());
idHolder.set(message.getId());
});
return idHolder.get();
}
}
private PersistentEntityStore openStore() {
return PersistentEntityStores.newInstance(DB_PATH);
}
}
✅ 核心机制:
- EntityStore 实体仅存在于事务内
- 需映射为DTO才能在仓库外使用
- 返回包含实体类型和唯一 ID 的 EntityId
4.3. findOne() 方法
添加查询方法:
public TaskEntity findOne(EntityId taskId) {
try (PersistentEntityStore entityStore = openStore()) {
AtomicReference<TaskEntity> taskEntity = new AtomicReference<>();
entityStore.executeInReadonlyTransaction(
txn -> taskEntity.set(mapToTaskEntity(txn.getEntity(taskId))));
return taskEntity.get();
}
}
映射方法实现:
private TaskEntity mapToTaskEntity(Entity entity) {
return new TaskEntity(entity.getProperty("description").toString(),
entity.getProperty("labels").toString());
}
4.4. findAll() 方法
实现全量查询:
public List<TaskEntity> findAll() {
try (PersistentEntityStore entityStore = openStore()) {
List<TaskEntity> result = new ArrayList<>();
entityStore.executeInReadonlyTransaction(txn -> txn.getAll(ENTITY_TYPE)
.forEach(entity -> result.add(mapToTaskEntity(entity))));
return result;
}
}
🚀 优势:
- 比环境 API 实现更简洁
- 直接调用 getAll() 方法遍历实体
4.5. deleteAll() 方法
简单粗暴的全量删除:
public void deleteAll() {
try (PersistentEntityStore entityStore = openStore()) {
entityStore.clear();
}
}
✅ 一行代码搞定所有数据清理
5. 总结
本文深入介绍了 JetBrains Xodus 的核心功能,展示了两种主要 API 的基本操作。作为嵌入式数据库方案,Xodus 在特定场景下是传统数据库的有效替代方案。
完整代码示例请查看 GitHub 仓库。