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

Spring Boot更新数据时报"Operation is not supported for read-only collection"错误如何解决

问题原因
  1. Kotlin 中listOf()返回的是只读不可变集合,本身不支持任何修改操作。
  2. 你的更新逻辑中构造了临时User对象(基于UserPostDTO生成),该临时对象的payments、topics关联字段默认初始化为listOf()生成的只读空集合。
  3. 自定义的User.copy()方法会将数据库查询到的原有实体的payments、topics字段,直接覆盖为上述临时对象的只读集合。
  4. Hibernate 要求实体的关联集合必须为可变集合,其内部会对集合做代理、脏检查等修改操作,当操作只读集合时就会抛出Operation is not supported for read-only collection异常。
解决方案

你可以选择任意一种适配你的业务需求:

  • 方案1:修改User类的自定义copy方法,移除不需要的关联集合拷贝逻辑(你的更新请求本身不会传递关联集合的修改信息,不需要覆盖原有值):
fun copy(user: User){
    firstName = user.firstName
    lastName = user.lastName
    birthDate = user.birthDate
    rating = user.rating
    // 删去以下两行,不要覆盖关联集合字段
    // payments = user.payments
    // topics = user.topics
}
  • 方案2:如果业务需要修改关联集合,将关联字段声明为可变集合,使用mutableListOf()初始化:
@OneToMany(mappedBy = "user")
var payments: MutableList<Payment> = mutableListOf(),

@OneToMany(mappedBy = "user")
var topics: MutableList<Topic> = mutableListOf()
  • 方案3:优化更新逻辑,无需构造临时User对象,直接用DTO字段更新数据库查询到的实体,避免多余的字段覆盖:
@PutMapping("/users/{id}")
fun updateUser(@PathVariable id: Long, @RequestBody userDTO: UserPostDTO){
    val userInDatabase = userService.getUser(id)
    if(userInDatabase.isEmpty) throw ResponseStatusException(HttpStatus.NOT_FOUND, "User not found")
    val extractedUser = userInDatabase.get()
    extractedUser.firstName = userDTO.firstName
    extractedUser.lastName = userDTO.lastName
    extractedUser.birthDate = userDTO.birthDate
    extractedUser.rating = userDTO.rating
    userService.saveUser(extractedUser)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 03:57:00