有人可以解释 JPA 和 Hibernate 中的 mappedBy 吗?
Posted
技术标签:
【中文标题】有人可以解释 JPA 和 Hibernate 中的 mappedBy 吗?【英文标题】:Can someone explain mappedBy in JPA and Hibernate? 【发布时间】:2012-02-24 20:45:50 【问题描述】:我是hibernate的新手,需要使用一对多和多对一的关系。这是我的对象中的双向关系,因此我可以从任一方向遍历。 mappedBy
是推荐的方法,但是,我无法理解。谁能解释一下:
为了我的例子,这里是我的带有注释的类:
Airline
拥有很多 AirlineFlights
许多 AirlineFlights
属于一个 Airline
航空公司:
@Entity
@Table(name="Airline")
public class Airline
private Integer idAirline;
private String name;
private String code;
private String aliasName;
private Set<AirlineFlight> airlineFlights = new HashSet<AirlineFlight>(0);
public Airline()
public Airline(String name, String code, String aliasName, Set<AirlineFlight> flights)
setName(name);
setCode(code);
setAliasName(aliasName);
setAirlineFlights(flights);
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="IDAIRLINE", nullable=false)
public Integer getIdAirline()
return idAirline;
private void setIdAirline(Integer idAirline)
this.idAirline = idAirline;
@Column(name="NAME", nullable=false)
public String getName()
return name;
public void setName(String name)
this.name = DAOUtil.convertToDBString(name);
@Column(name="CODE", nullable=false, length=3)
public String getCode()
return code;
public void setCode(String code)
this.code = DAOUtil.convertToDBString(code);
@Column(name="ALIAS", nullable=true)
public String getAliasName()
return aliasName;
public void setAliasName(String aliasName)
if(aliasName != null)
this.aliasName = DAOUtil.convertToDBString(aliasName);
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name="IDAIRLINE")
public Set<AirlineFlight> getAirlineFlights()
return airlineFlights;
public void setAirlineFlights(Set<AirlineFlight> flights)
this.airlineFlights = flights;
航空公司航班:
@Entity
@Table(name="AirlineFlight")
public class AirlineFlight
private Integer idAirlineFlight;
private Airline airline;
private String flightNumber;
public AirlineFlight()
public AirlineFlight(Airline airline, String flightNumber)
setAirline(airline);
setFlightNumber(flightNumber);
@Id
@GeneratedValue(generator="identity")
@GenericGenerator(name="identity", strategy="identity")
@Column(name="IDAIRLINEFLIGHT", nullable=false)
public Integer getIdAirlineFlight()
return idAirlineFlight;
private void setIdAirlineFlight(Integer idAirlineFlight)
this.idAirlineFlight = idAirlineFlight;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="IDAIRLINE", nullable=false)
public Airline getAirline()
return airline;
public void setAirline(Airline airline)
this.airline = airline;
@Column(name="FLIGHTNUMBER", nullable=false)
public String getFlightNumber()
return flightNumber;
public void setFlightNumber(String flightNumber)
this.flightNumber = DAOUtil.convertToDBString(flightNumber);
编辑:
数据库架构:
AirlineFlights 将 idAirline 作为 ForeignKey,而 Airline 没有 idAirlineFlights。这使得 AirlineFlights 成为所有者/识别实体?
理论上,我希望航空公司成为航空公司航班的所有者。
【问题讨论】:
【参考方案1】:MappedBy 向 hibernate 发出信号,表明关系的键在另一端。
这意味着尽管您将 2 个表链接在一起,但其中只有 1 个表对另一个表有外键约束。 MappedBy 允许您仍然从不包含约束的表链接到另一个表。
【讨论】:
你能再澄清一下吗? @Kurt Du Bois,您为什么要使用mappedBy
而不是定义双向(每边都有 foreign_key 约束)?
因为有时候把钥匙放在两边是没有意义的。例如,假设您有一家公司和一台便携式设备。一台便携机只属于一家公司,但一家公司会有多台便携机。
很抱歉编辑人员回滚了我的答案,但实际上您的编辑没有任何附加价值。最后一句话甚至没有意义。
@KurtDuBois 如此映射,只是进入图片如何创建您的数据库,即您使用 mappedby 或在 java 端不休眠的行为类似。是吗?【参考方案2】:
通过在两个模型上指定@JoinColumn
,您没有双向关系。您有两种单向关系,以及一种非常混乱的映射关系。您告诉两个模型他们“拥有” IDAIRLINE 列。真的只有其中一个真正应该! '正常'的事情是将@JoinColumn
完全从@OneToMany
端移除,而是将mappedBy 添加到@OneToMany
。
@OneToMany(cascade = CascadeType.ALL, mappedBy="airline")
public Set<AirlineFlight> getAirlineFlights()
return airlineFlights;
这告诉 Hibernate“去查看名为 'airline' 的 bean 属性,在我收集的东西上找到配置。”
【讨论】:
我对您最后关于 mappedBy 的描述感到有些困惑。事物在 db 中的组织方式是否重要? @DB:AirlineFlights 将 idAirline 作为外键。航空公司只有 idAirline 作为主键,不包含有关 AirlineFlights @ DB 的信息。 是的,这很重要。 mappedBy 中的名称告诉 Hibernate 在哪里可以找到 JoinColumn 的配置。 (在 AirlineFlight 的 getAirline() 方法上。)您将 JoinColumn 放在航空公司上的映射方式是告诉 Airline 它 负责维护另一个表中的值。可以告诉实体它“拥有”不同表中的列并负责更新它。这不是您通常想要做的事情,并且可能会导致 SQL 语句的执行顺序出现问题。 请查看编辑。在数据库级别,airlineFlight 表拥有 idAirline 作为外键列。因此,JoinColumn 应该放在相应的 ManytoOne 中的航空公司航班类/表上,因为它拥有该列? 是的,我建议这样做。这是最简单的选择,您似乎不需要任何其他东西。 “将@JoinColumn 完全从@OneToMany 一侧移除”您的意思是@ManyToOne
一侧,对吧?【参考方案3】:
mappedby
不言自明,它告诉 hibernate 不要映射这个字段。它已被此字段 [name="field"] 映射。
字段在另一个实体(name of the variable in the class not the table in the database)
..
如果你不这样做,hibernate 将映射这两个关系,因为它不是 相同的关系
所以我们需要告诉 hibernate 只在一侧进行映射并在它们之间进行协调。
【讨论】:
is mappedBy 是可选的吗?因为不使用 mappedBy 我得到了相同的结果,即双向对象映射 你不能使用 on2many 和 many2one 而不在一侧使用 mappedBy 对于 many2many 你必须在一侧使用 mappedBy 感谢您指出属性值的含义,即另一个表中的字段名称。 也许hibernate并不总能自己说话,但当它说话时,至少它使用标点符号 对我来说,它本身并不能说明问题;相反,它非常混乱。只需查看有关mappedBy
和 inversedBy
的实际问题的数量即可。其他 ORM 使用更智能的 belongsToMany
、hasMany
属性。【参考方案4】:
mappedby="在另一个类中创建的同一类实体的对象"
注意:-Mapped by 只能在一个类中使用,因为一张表必须包含外键约束。如果mapped by 可以在两边都应用,那么它会从两个表中删除外键,如果没有外键,两个表就没有关系。
注意:- 它可用于以下注释:- 1.@OneTone 2.@OneToMany 3.@ManyToMany
注意---它不能用于以下注释:- 1.@ManyToOne
一对一:- 在映射的任何一侧执行,但仅在一侧执行。 它将删除应用它的类的表上的外键约束的额外列。
例如。如果我们在员工对象上应用 Employee 类中的映射,则 Employee 表中的外键将被删除。
【讨论】:
【参考方案5】:您从 ManyToOne 映射开始,然后将 OneToMany 映射也用于双向方式。 然后在 OneToMany 方面(通常是您的父表/类),您必须提及“mappedBy”(映射由子表/类完成),因此休眠不会在 DB 中创建 EXTRA 映射表(如 TableName = parent_child)。
【讨论】:
【参考方案6】:表关系与实体关系
在关系数据库系统中,one-to-many
表关系如下所示:
请注意,该关系基于子表中的外键列(例如,post_id
)。
因此,在管理 one-to-many
表关系时,只有一个事实来源。
现在,如果您采用映射到我们之前看到的 one-to-many
表关系的双向实体关系:
如果你看一下上面的图表,你可以看到有两种方法来管理这种关系。
在Post
实体中,您有comments
集合:
@OneToMany(
mappedBy = "post",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostComment> comments = new ArrayList<>();
并且,在PostComment
中,post
关联映射如下:
@ManyToOne(
fetch = FetchType.LAZY
)
@JoinColumn(name = "post_id")
private Post post;
因为有两种方式来表示外键列,所以在将关联状态更改转换为其等效的外键列值修改时,您必须定义哪个是事实来源。
映射依据
mappedBy
属性告诉@ManyToOne
侧负责管理外键列,并且该集合仅用于获取子实体并将父实体状态更改级联到子实体(例如,删除父级也应该删除子实体)。
同步双向关联的双方
现在,即使您定义了mappedBy
属性并且子端@ManyToOne
关联管理外键列,您仍然需要同步双向关联的双方。
最好的方法是添加这两个实用方法:
public void addComment(PostComment comment)
comments.add(comment);
comment.setPost(this);
public void removeComment(PostComment comment)
comments.remove(comment);
comment.setPost(null);
addComment
和 removeComment
方法确保双方同步。因此,如果我们添加子实体,子实体需要指向父实体,并且父实体应该将子实体包含在子集合中。
【讨论】:
你能详细说明一下实用方法吗,我有点困惑为什么我们需要同步,因为在正确映射之后,事实的来源只是多方面的,即,发表评论。是不是在addComment
中我们已经在评论对象中设置了帖子?此外,如果我们只是对 comment
执行删除作为一个单独的实体就足够了?
This article 解释了为什么需要实用方法。【参考方案7】:
mappedBy 属性表征双向关联,必须在父端设置。换句话说,对于双向 @OneToMany 关联,将 mappedBy 设置为父侧的 @OneToMany 并在 mappedBy 引用的子侧添加 @ManyToOne 。通过 mappedBy,双向 @OneToMany 关联表明它反映了 @ManyToOne 子端映射。
【讨论】:
以上是关于有人可以解释 JPA 和 Hibernate 中的 mappedBy 吗?的主要内容,如果未能解决你的问题,请参考以下文章
Spring Data JPA Vs Hibernate JPA Vs JPA
JPA 和 Hibernate 中的 persist() 和 merge() 有啥区别?
Hibernate JPA中@Transient@JsonIgnoreProperties@JsonIgnore@JsonFormat@JsonSerialize等注解解释