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

Hibernate使用JsonBinaryType无变更却更新实体问题咨询

解决Hibernate乐观锁下JSON属性误判脏数据导致版本号无故提升的问题

问题场景

  • 技术栈:Spring Boot 3.2、Hibernate 6.3、hypersistence-utils-hibernate-63:3.7.0
  • 实体字段定义:
    @Type(JsonBinaryType::class)
    @Column(name = "errors")
    var verrors: Map<String, List<Error>> = emptyMap()
    
  • 异常现象:仅在**session-in-view(视图内会话)**场景下,只要verrors属性有值,实体的乐观锁版本号就会被自动提升;直接调用服务层方法则不会触发此问题
  • 预期效果:未实际修改属性内容时,实体不应触发更新(类似事务设为只读时的表现)

根因分析

Hibernate的脏检查机制在session-in-view模式下,会将从数据库加载的纯字符串格式JSON数据,与会话中反序列化生成的基于Error对象的Map-List内存结构做对比。由于两者的对象引用、内存存储形式不同,Hibernate误判该属性为脏数据,进而触发版本号更新操作。

可行解决方案

1. 自定义JSON类型,修正equals逻辑

扩展JsonBinaryType,重写isEqual方法,通过序列化后的JSON字符串对比内容,而非直接对比对象实例:

class CustomJsonBinaryType : JsonBinaryType() {
    private val objectMapper = ObjectMapper()

    override fun isEqual(x: Any?, y: Any?): Boolean {
        if (x === y) return true
        if (x == null || y == null) return false
        return try {
            objectMapper.writeValueAsString(x) == objectMapper.writeValueAsString(y)
        } catch (e: JsonProcessingException) {
            false
        }
    }
}

修改实体字段的类型注解:

@Type(CustomJsonBinaryType::class)
@Column(name = "errors")
var verrors: Map<String, List<Error>> = emptyMap()

2. 手动脱离会话,避免自动脏检查

在控制器或服务层加载实体后,调用entityManager.detach()将实体从会话中移除,阻止Hibernate后续的脏检查:

@Autowired
private lateinit var entityManager: EntityManager

fun getEntity(id: Long): Entity {
    val entity = entityManager.find(Entity::class.java, id)
    entityManager.detach(entity)
    return entity
}

注意:此方法仅适用于后续无需对该实体做持久化修改的场景。

3. 关闭全局session-in-view,按需控制会话

通过Spring配置关闭全局的session-in-view,避免会话长时间打开导致不必要的脏检查:

spring.jpa.open-in-view=false

之后在需要会话支持的方法上,通过@Transactional注解手动开启事务,控制会话范围。

4. 标记字段为不可变(适用于只读属性)

如果verrors属性在业务中不会被修改,可添加@Immutable注解告知Hibernate跳过该字段的脏检查:

@Type(JsonBinaryType::class)
@Column(name = "errors")
@Immutable
var verrors: Map<String, List<Error>> = emptyMap()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 05:12:36