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

Spring Boot从2.6.7升级至2.7.2时触发TransientPropertyValueException

问题原因与解决方案

核心原因

Spring Boot 2.7.2 升级了依赖的 Hibernate 版本(至 5.6.x 系列),该版本对关联实体的状态校验逻辑变得更严格,同时 Spring Boot 2.7 默认启用了 hibernate.check_nullability=true 配置,会在持久化前严格检查关联实体的状态。

你的代码在 2.6.7 版本正常,主要因为旧版 Hibernate 对 detached(脱离当前会话)状态的实体校验更宽松,甚至会自动合并这类实体;而升级后,Hibernate 要求关联的非空实体必须处于托管(Managed)状态(即存在于当前 Hibernate Session 中),否则判定为 transient(未持久化)状态,抛出异常。

如果你的测试类没有标注 @Transactional,@BeforeEach 中的 addressRepository.save(address) 会在独立事务中执行并提交,此时 address 虽已持久化,但进入测试方法后,当前 Session 中没有该实例,它处于 detached 状态,这就是 Hibernate 报错的直接原因。

解决方案

方案一:为测试类添加事务注解

将 @Transactional 添加到测试类上,让 @BeforeEach 和测试方法共享同一个事务,这样 save 后的 address 会一直处于当前 Session 的托管状态,保存 Building 时 Hibernate 能正确识别其持久化状态:

@SpringBootTest
@Transactional
class YourIntegrationTest {
    @Autowired
    private AddressRepository addressRepository;
    @Autowired
    private BuildingRepository buildingRepository;

    @BeforeEach
    void init(){
        Address address = new Address();
        // 初始化address字段
        address = addressRepository.save(address);

        Building building = new Building();
        building.setAddress(address); 
        buildingRepository.save(building);
    }

    // 测试方法
}

注:默认情况下,测试事务会在方法结束后自动回滚,不会污染测试数据库。

方案二:重新加载address到当前会话

如果不想使用全局事务,可以在 save address 后,通过 repository 的查询方法重新获取实例,确保它进入当前 Session 的托管状态:

@BeforeEach
void init(){
    Address address = new Address();
    // 初始化address字段
    address = addressRepository.save(address);
    // 重新加载,将实例纳入当前会话
    address = addressRepository.findById(address.getId()).orElseThrow();

    Building building = new Building();
    building.setAddress(address); 
    buildingRepository.save(building);
}

方案三:关闭Hibernate严格校验(不推荐)

在测试环境配置文件(application-test.properties)中关闭空值校验,绕过这个错误,但会降低数据一致性校验能力,隐藏潜在问题:

spring.jpa.properties.hibernate.check_nullability=false

额外检查点

  1. 确保 Address 实体的 ID 字段配置了正确的生成策略,比如:
@Entity
class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    // 其他字段与方法
}
  1. 确保 Building 实体的 address 字段有合法的 getter/setter 方法,或 Hibernate 能通过反射访问该字段(比如字段为 public,或配置了 @AccessType 注解)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 05:54:19