You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android使用hapi-fhir更新Patient触发ResourceVersionConflictException

问题根因

ResourceVersionConflictException对应HTTP 409 Conflict,是FHIR服务端乐观锁校验拦截请求导致的:你提交更新请求时携带的资源版本号,和服务端当前存储的该资源最新版本号不匹配,请求会被直接拒绝。
结合Android端hapi-fhir的使用场景和你贴的代码,90%以上的情况是你提交的Patient对象丢失了meta字段中的versionId版本标识,常见触发场景:

  • 读取到Patient对象后,使用Gson、FastJSON等通用JSON序列化工具将对象持久化到本地(Room、SharedPreferences等),后续反序列化后再提交更新。HAPI资源模型的meta.versionId、资源ID等字段和内置解析器绑定,通用序列化工具默认不会序列化这类内部字段,反序列化后版本号直接为null。
  • 修改资源属性时意外覆盖了patient.meta字段,导致版本号丢失。
  • 少数场景是读取资源后,有其他客户端/线程提前修改了服务端的该Patient资源,你持有的版本已经过期。
排查方法

在调用update接口前加一行日志,确认版本号是否存在:

println("待更新资源版本号:${patient.meta?.versionId ?: "版本号为空"}")

如果输出为「版本号为空」,即可确认是版本标识丢失导致的冲突。

修复方案

方案1:正确携带版本号(推荐,符合FHIR规范)

这是最稳妥的实现方式,不会误覆盖其他端提交的修改:

  • 如果你有持久化资源的需求,不要用通用JSON工具序列化HAPI资源对象,改用HAPI内置的解析器做序列化/反序列化:
    val fhirParser = client.fhirContext.newJsonParser()
    // 持久化时转JSON字符串
    val patientStr = fhirParser.encodeResourceToString(patient)
    // 读取本地存储的JSON时转回资源对象
    val localPatient = fhirParser.parseResource(Patient::class.java, patientStr)
    
  • 如果不方便调整序列化逻辑,可以在读取到资源后单独存储版本号,更新前手动赋值回资源对象,同时在更新请求中显式指定版本匹配:
    // 读取到资源后立刻存下版本号
    val version = patient.meta.versionId.toLong()
    
    // --- 修改名字逻辑 ---
    val newName = .....
    val humanName = if (patient.name == null){
        patient.addName()
    }else{
        if (patient.name.isEmpty()){ patient.addName() } else patient.name[0]
    }
    if (humanName.given.isEmpty()){
        humanName.addGiven(newName)
    }else{
        // 注意不要直接改value字段,用setValue方法赋值
        humanName.given[0].setValue(newName)
    }
    
    // 更新前手动补全版本号
    patient.meta.versionId = version.toString()
    val resp = client.update()
        .resource(patient)
        .withMatchVersion(version) // 显式携带If-Match请求头
        .encodedJson()
        .execute()
    

方案2:跳过版本校验(仅用于调试,不推荐生产环境用)

如果不需要乐观锁保护,可以直接强制覆盖服务端最新版本,注意该操作可能覆盖其他用户提交的修改:

val resp = client.update()
    .resource(patient)
    .withMatchVersion(null) // 传null跳过版本校验
    .encodedJson()
    .execute()
额外注意

你修改Given名称的代码存在一个隐患:直接操作humanName.given[0].value字段赋值,不会触发HAPI模型的内部变更标记,可能导致序列化时值丢失,应该调用setValue()方法完成赋值。


内容的提问来源于stack exchange,提问作者Abu Yousuf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 03:27:26