了解Hibernate中的mappedBy注释

时间:2014-08-18 20:25:39

标签: java hibernate jpa

我想了解JPA中mappedBy注释的@OneToMany属性。我创建了以下示例,其中Customer有一个Orders列表:

@Entity
public class Customer {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   @OneToMany(mappedBy="customer")
   @OrderColumn(name="orders_index")
   public List<Order> getOrders() { return orders; }
   public void setOrders(List<Order> orders) { this.orders = orders; }
   private List<Order> orders;
}

@Entity
@Table(name="TBL_ORDER")
public class Order {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   public int getOrderNumber() { return orderNumber; }
   public void setOrderNumber(int orderNumber) { this.orderNumber = orderNumber; }
   private int orderNumber;

   @ManyToOne
   public Customer getCustomer() { return customer; }
   public void setCustomer(Customer customer) { this.customer = customer; }
   private Customer customer;
}

现在当我使用Hibernate生成表时,我发现Hibernate只创建了2个表:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), orders_index number(10,0), primary key (id))
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

此外,如果我尝试保存客户和一些订单,我会在下面看到Hibernate生成的DML语句:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: update TBL_ORDER set orders_index=? where id=?

为什么hibernate尝试在TBL_ORDER中插入和更新记录而不是仅运行单个插入查询?

现在,如果我删除mappedBy属性并尝试生成表,这次我会看到3个表:

Hibernate: create table Customer (id number(10,0) not null, primary key (id))
Hibernate: create table Customer_TBL_ORDER (Customer_id number(10,0) not null, orders_id number(10,0) not null, orders_index number(10,0) not null, primary key (Customer_id, orders_index))
Hibernate: create table TBL_ORDER (id number(10,0) not null, orderNumber number(10,0) not null, customer_id number(10,0), primary key (id))
Hibernate: alter table Customer_TBL_ORDER add constraint UK_sw94jktvh72tripj876s31052  unique (orders_id)
Hibernate: alter table Customer_TBL_ORDER add constraint FK_sw94jktvh72tripj876s31052 foreign key (orders_id) references TBL_ORDER
Hibernate: alter table Customer_TBL_ORDER add constraint FK_f03up2h945cg0dcbo2pdb1d3c foreign key (Customer_id) references Customer
Hibernate: alter table TBL_ORDER add constraint FK_nt24krtgqwcsynosqgk4jkvfv foreign key (customer_id) references Customer

为什么hibernate会在这种情况下创建一个额外的表? mappedBy属性如何控制它?为什么我们在Customer_TBL_ORDER表中的orders_id列上有一个额外的唯一键约束?

现在,如果我尝试保存客户及其订单,我将接受DML操作:

Hibernate: insert into Customer (id) values (?)
Hibernate: insert into TBL_ORDER (customer_id, orderNumber, id) values (?, ?, ?)
Hibernate: insert into Customer_TBL_ORDER (Customer_id, orders_index, orders_id) values (?, ?, ?)

与我声明mappedBy属性的情况相比,为什么我们在这种情况下没有额外的更新查询?

3 个答案:

答案 0 :(得分:21)

这是正常的。

使用mappedBy,您直接告诉Hibernate / JPA一个表拥有该关系,因此它存储为该表的一列。

没有,关系是外部的,Hibernate / JPA需要创建另一个表来存储关系。

示例:

  • stackoverflow Question有多个Answer
  • Answer由一个Question所拥有。

在纯JDBC中,您将创建两个表:

Questions(Question_ID, ...);
Answers(Answer_ID, Question_ID, ...);

其中Question_ID是引用Question.Question_ID的外键。

至于另一种情况,我没有一个真实的案例,因为几乎每次都有一个独特的约束(例如:a Question可能有几个{ {1}},而Answer可能实际上有多个Answer,但对于任何Question只出现一次。

答案 1 :(得分:13)

OneToMany有两种主要方式可以在数据库中完成。

  1. 使用关系表(M:M)
  2. 在目标表中使用外键。 (1:M)
  3. 如果您保留OneToMany映射并将其设置为默认值,则默认情况下将使用关系表,这是您似乎想要的。如果您不想使用连接表,您可以指定JoinColumn设置外键关系,就像OneToOne一样,但是在相反的方向 - 它告诉提供商什么目标表中的字段指向此实体的主键。但通常目标外键在目标实体中映射 - 毕竟它是ManyToOne - 因此mappedby用于指定此OneToMany应使用已定义的关系目标实体。

    在这种情况下,mappedBy=customer告诉它查看Order实体中的customer属性映射。在那里,它发现客户的ManyToMany映射具有默认的joinColumn customer_id,它也用于OneToMany。由于它已在Order实体中映射,因此OneToMany是只读的。这确保了如果两个关系不同步,JPA有一方始终信任并用于设置数据库字段。

答案 2 :(得分:2)

正常此行为mappedBy仅表示此方面的实体是关系的倒数,而所有者驻留在“其他”实体中。

我建议你link