【问题标题】:Why does FetchType.Eager prevent org.hibernate.TransientObjectException in bidirectional mapping while CascadeType.ALL has no effect?为什么 FetchType.Eager 阻止双向映射中的 org.hibernate.TransientObjectException 而 CascadeType.ALL 没有效果?
【发布时间】:2025-12-21 19:45:15
【问题描述】:

用 .jsp 中的数据填充表单支持 bean(状态)后,我尝试将其添加到其父实体(员工)。不幸的是,这会导致 org.hibernate.TransientObjectException。

在某些线程中建议将 CascadeType.ALL 添加到 @ManyToOne(拥有方,Status.java)没有效果,这应该是正确的。但是除了 CascadeType.ALL 之外,在 @OneToMany(引用端,Employee.java)上添加 fetch = FetchType.EAGER 可以解决问题(如下面的代码所示)。

模型“员工”

@Entity
public class Employee {

@OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Status> statusList = new ArrayList<Status>();

public void addStatus(Status status) {
    this.statusList.add(status);
    status.setEmployee(this);
 }
}

模型“状态”

@Entity
public class Status implements Comparable<Status> {

@ManyToOne
@JoinColumn(name = "employee_id")
private Employee employee;

}

控制器

@Controller
public class DashboardController {

@PostMapping("addStatus")
public String addStatus(@Valid @ModelAttribute("newStatus") Status newStatus Principal principal) {

Employee employee = employeeService.getEmployeeByPosition(principal.getName());
        employee.addStatus(newStatus);
        employeeService.updateEmployee(employee);
 }
}

服务

@Service
public class EmployeeService {
public void updateEmployee(Employee employee) {
    employeeRepo.save(employee);
 }
}

我希望 @OneToMany 端的 CascadeType.ALL 就足够了。但这会导致

HHH000346:托管刷新期间出错 [org.hibernate.TransientObjectException:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例:....model.Status]

另一方面,当我另外使用 FetchType.EAGER 时,异常消失了,我无法理解。

【问题讨论】:

    标签: java hibernate spring-boot spring-mvc spring-data-jpa


    【解决方案1】:

    最有可能:

    Employee employee = employeeService.getEmployeeByPosition(principal.getName());
    

    这发生在事务 1

    employee.addStatus(newStatus);
    

    这里的实体已经处于分离状态,如果不急切,LAZY 加载将无法从此时开始。

    employeeService.updateEmployee(employee);
    

    事务 2 中,您很可能在内部尝试 merge,但该集合尚未延迟加载。使用EAGER 即可,合并成功。

    【讨论】:

    • 如果statusList集合未加载,这不应该导致空指针异常吗?
    • 它应该抛出一个惰性初始化异常,这是真的。
    • 但它没有:(我尝试将控制器中的所有逻辑放入服务方法中并添加@Transactional但没有成功。应用程序流程有什么问题吗?我可以提供任何其他有用的信息? 现在我保留了 Lazy-Fetching 并在调用 employeeService.updateEmployee(employee); 使其工作之前通过新的 StatusService(调用 StatusReposittory)保存了状态。推荐的处理方法是什么?
    • @MaciejKowalski 你是对的!没有抛出 LazyInitializationException 的原因是默认情况下 spring boot 使用 Open Session In View Pattern。一旦我在 application.properties 中设置spring.jpa.open-in-view=false,就会抛出异常。
    最近更新 更多