为何JPA双向ManyToOne/OneToMany关联中无法使用mappedBy?
1. 某一端“拥有关系所有权”指什么?
关系所有权的核心是谁负责维护数据库中外键字段的同步更新。在双向关联中,只有拥有所有权的一端,其关联关系的修改(比如为多端实例设置所属的一端、移除关联关系)会被JPA映射到数据库的外键字段变更;没有所有权的一端只是“视图层”的反向关联,仅用于查询或对象层面的访问,直接修改这一端的关联集合不会触发数据库的外键更新。
举个实际代码例子:
// 多端(拥有关系所有权) @Entity public class OrderItem { @Id private Long id; @ManyToOne @JoinColumn(name = "order_id") // 明确指定数据库外键字段,这端负责维护关系 private Order order; // getter、setter } // 一端(无所有权,仅反向关联) @Entity public class Order { @Id private Long id; @OneToMany(mappedBy = "order") // mappedBy声明:关系所有权在OrderItem的order字段 private List<OrderItem> items = new ArrayList<>(); // getter、setter }
在这个例子里,当你执行orderItem.setOrder(order)时,JPA会自动更新order_item表的order_id字段;但如果只是执行order.getItems().add(orderItem),数据库的外键不会有任何变化——必须同时设置orderItem.setOrder(order),才能完成关联关系的持久化。
2. 为何ManyToOne端不能使用mappedBy?
原因很直接:mappedBy的作用是声明当前端不拥有关系所有权,所有权在另一端,但ManyToOne对应的多端,是数据库中外键字段的实际存储位置(外键在多端表中),这一端天然必须承担维护外键的职责,不可能把所有权转移到没有外键字段的一端。
从逻辑上看:OneToMany对应的一端表中,根本不存在关联多端的外键字段(外键在多端表),如果允许ManyToOne端用mappedBy,就意味着要让OneToMany端来维护外键,但OneToMany端没有对应的数据库字段可以操作,JPA根本无法完成外键的更新,这在设计上完全不成立。
所以JPA的规范强制规定:双向ManyToOne/OneToMany关联中,ManyToOne端必须作为关系所有者(负责维护外键),OneToMany端只能通过mappedBy声明反向关联,不能反过来。
内容的提问来源于stack exchange,提问作者Stupido

