public IndexResponse save(String indexNameOrAlias, String id, long version, Object source, Refresh refresh) throws IOException { Assert.notEmpty(indexNameOrAlias, "indexNameOrAlias不能为空"); Assert.notEmpty(source, "source不能为空"); JsonNode node = toJsonNode(source); return elasticsearchClient.index(indexRequest -> indexRequest.index(indexNameOrAlias).id(id).version(version).document(node).refresh(refresh) ); } 这里version(version)的作用是什么?
在 Elasticsearch Java 客户端中,version(version) 方法用于指定乐观并发控制的版本号。它的主要作用是:
1. 乐观锁机制
- 确保在并发更新时,文档不会被覆盖
- 每次文档更新时,版本号会自动递增
- 更新时会检查传入的版本号是否与当前文档的版本号一致
2. 具体作用
JAVA
// 示例:更新版本号为 5 的文档
elasticsearchClient.index(indexRequest ->
indexRequest.index(indexNameOrAlias)
.id(id)
.version(5) // 指定版本号
.document(node)
.refresh(refresh)
);
执行逻辑:
- 如果文档当前版本号是 5 → 更新成功,版本号变为 6
- 如果文档当前版本号不是 5 → 抛出
VersionConflictEngineException
3. 常见使用场景
JAVA
// 场景1:基于最新版本更新(避免数据覆盖)
IndexResponse response = save(index, docId, lastVersion, updatedData, refresh);
// 如果期间有其他人修改了文档,lastVersion 不匹配,操作失败
// 场景2:强制更新(覆盖最新版本)
save(index, docId, 0, data, refresh); // version=0 表示不使用版本控制
// 场景3:基于特定版本更新
save(index, docId, expectedVersion, data, refresh);
4. 版本号类型
JAVA
// 内部版本号(默认)
indexRequest.version(5L); // 必须为正值
// 外部版本号(需要指定版本类型)
indexRequest.version(5L)
.versionType(VersionType.EXTERNAL); // 外部系统控制的版本号
5. 实际示例
JAVA
// 假设您有一个订单更新场景
public void updateOrderWithVersion(String orderId, long currentVersion, Order newData) throws IOException {
// 只有当文档版本是 currentVersion 时才更新
IndexResponse response = elasticsearchRepository.save(
"orders",
orderId,
currentVersion, // 传入当前知道的版本号
newData,
Refresh.Wait_For
);
// 如果更新成功,返回新的版本号
long newVersion = response.version();
System.out.println("更新成功,新版本: " + newVersion);
}
6. 注意事项
- version=0:表示"创建文档",如果文档已存在会失败
- version>0:表示更新,必须匹配现有文档的版本
- 如果不指定版本号,Elasticsearch 会自动管理版本,但无法保证并发更新时的数据一致性
- 在高并发场景中,使用版本控制可以有效防止"丢失更新"问题
在您的方法中,传入的 version 参数就是这个用于乐观并发控制的版本号。