一、映射多对一关联关系。

1.单向的多对一

(1)以 Customer 和 Order 为例:一个用户可以发出多个订单,而一个订单只能属于一个客户。从 Order 到 Customer 是多对一关联关系。

(2)创建 Customer 和 Order 表。

CREATE TABLE customer (
customer_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
customer_name VARCHAR(50)
) CREATE TABLE `order` (
order_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
order_name VARCHAR(50),
customer_id INT(11)
)

Create

(3)用 Intellij Idea 自动生成关联关系,以及对应的 Entitiy.hbm.xml 和 持久化类。

说明:

其中 Type 是用来修饰对应的 Attribute Name 的。

在 Order 端,定义 Customer 类,一个订单属于一个客户。而在 Customer 端,一个客户可以有多个订单,因为是单向的,所以这里放弃属性的添加。

在 Join Columns 定义了 Order 和 Customer 之间的关联关系,order 表中的 customer_id 外键和 customer 表中的 customer_id 主键关联。

来看生成的 Schema:

没有勾选 customer_id,是因为 Intellij Idea 没法直接映射为 Customer 类型的 customer。

<hibernate-mapping>

    <class name="com.nucsoft.hibernate.Order" table="order" schema="hibernate">
<id name="orderId">
<column name="order_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="orderName">
<column name="order_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
<many-to-one name="customer" class="com.nucsoft.hibernate.Customer">
<column name="customer_id" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>

Order.hbm.xml

使用 <many-to-one> 节点来维护多对一关联关系。

name 属性:多这一端关联的一那一端的属性的名称。

class 属性:关联的一端的属性的类型。

column 属性:一那一端在多的一端对应的数据表中的外键。可以任意命名,但需要和数据表中的字段对应。

(4)单向多对一的 CRUD 以及需要注意的问题。

<1> 新增

①先保存一的一端 Customer,后保存多的一端 Order。

@Test
public void testMany2OneSave() {
Customer customer = new Customer();
customer.setCustomerName("aa"); Order order = new Order();
order.setOrderName("order1");
order.setCustomer(customer); Order order2 = new Order();
order2.setOrderName("order2");
order2.setCustomer(customer); session.save(customer);
session.save(order);
session.save(order2);
}

Save.java

打印 SQL:

Hibernate:
insert
into
hibernate.customer
(customer_name)
values
(?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)

Output

结论:发送了3条 INSERT 语句。

②先保存多的一端 Order,再保存一的一端 Customer。

@Test
public void testMany2OneSave() {
Customer customer = new Customer();
customer.setCustomerName("bb"); Order order = new Order();
order.setOrderName("order3");
order.setCustomer(customer); Order order2 = new Order();
order2.setOrderName("order4");
order2.setCustomer(customer); session.save(order);
session.save(order2);
session.save(customer);
}

Save2.java

打印 SQL:

Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.customer
(customer_name)
values
(?)
Hibernate:
update
hibernate.order
set
order_name=?,
customer_id=?
where
order_id=?
Hibernate:
update
hibernate.order
set
order_name=?,
customer_id=?
where
order_id=?

Output2

结论:发送了3条 INSERT 语句,2条 UPDATE 语句。

总结:在单向多对一的关联关系下,先插入 1 的一端会减少 SQL 语句的执行,性能更高。

<2>删除

先删除1的一端。

@Test
public void testMany2OneDelete() {
Customer customer = (Customer) session.get(Customer.class, 1);
session.delete(customer);
}

Delete.java

控制台打印:

Cannot delete or update a parent row: a foreign key constraint fails (`hibernate`.`order`, CONSTRAINT `FK_m6q2ofkj1g5aobtb2p00ajpqg` FOREIGN KEY (`customer_id`)  REFERENCES `customer` (`customer_id`))

结论:在不设置级联关系的前提下,不能删除 1 的一端。

<3>更新

@Test
public void testMany2OneUpdate() {
Order order = (Order) session.get(Order.class, 1);
order.getCustomer().setCustomerName("aaa");
}

Update.java

Hibernate:
select
order0_.order_id as order_id1_1_0_,
order0_.order_name as order_na2_1_0_,
order0_.customer_id as customer3_1_0_
from
hibernate.order order0_
where
order0_.order_id=?
Hibernate:
select
customer0_.customer_id as customer1_0_0_,
customer0_.customer_name as customer2_0_0_
from
hibernate.customer customer0_
where
customer0_.customer_id=?
Hibernate:
update
hibernate.customer
set
customer_name=?
where
customer_id=?

Output

<4>查询

①查询 n 的一端,但是不使用查询出来关联的 1 的一端的对象。

@Test
public void testMany2OneGet() {
Order order = (Order) session.get(Order.class, 1);
System.out.println(order.getCustomer().getClass().getName());
}
Hibernate:
select
order0_.order_id as order_id1_1_0_,
order0_.order_name as order_na2_1_0_,
order0_.customer_id as customer3_1_0_
from
hibernate.order order0_
where
order0_.order_id=?
order1
com.nucsoft.hibernate.Customer_$$_jvst30c_1

②查询 n 的一端,使用查询出来关联的 1 的一端的对象。

@Test
public void testMany2OneGet() {
Order order = (Order) session.get(Order.class, 1);
System.out.println(order.getCustomer().getClass().getName());
order.getCustomer().getCustomerName();
}
Hibernate:
select
order0_.order_id as order_id1_1_0_,
order0_.order_name as order_na2_1_0_,
order0_.customer_id as customer3_1_0_
from
hibernate.order order0_
where
order0_.order_id=?
com.nucsoft.hibernate.Customer_$$_jvst30c_1
Hibernate:
select
customer0_.customer_id as customer1_0_0_,
customer0_.customer_name as customer2_0_0_
from
hibernate.customer customer0_
where
customer0_.customer_id=?

总结:可以发现,采用的是懒加载机制,即获取到的 1 的一端的对象是一个代理对象。只有在使用这个对象的属性的情况下,才会发送 SQL 语句。

③ 由懒加载机制引发的 懒加载异常。

@Test
public void testMany2OneGet() {
Order order = (Order) session.get(Order.class, 1);
System.out.println(order.getCustomer().getClass().getName());
session.close();
order.getCustomer().getCustomerName();
}
org.hibernate.LazyInitializationException: could not initialize proxy - no Session

在需要使用对象之前,关闭了 Session 连接,由此会引发 LazyInitializationException 异常。

2.双向的多对一

(1)还是以 Order 和 Customer 为例:双向的多对一不仅仅要在 Order 类中定义一个 Customer 属性,而在 Customer 类中也需定义存放 Order 对象的集合属性。

(2)创建 Order  和 Customer 表和创建单向多对一相同。

(3)通过 Intellij Idea 生成简单的持久化类和 Entity.hbm.xml 文件。手动的去建立关联关系。

<1>生成简单的持久化类 和 Entity.hbm.xml 文件

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-11-13:23
*/
public class Customer {
private Integer customerId;
private String customerName; public Integer getCustomerId() {
return customerId;
} public void setCustomerId(Integer customerId) {
this.customerId = customerId;
} public String getCustomerName() {
return customerName;
} public void setCustomerName(String customerName) {
this.customerName = customerName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Customer customer = (Customer) o; if(customerId != null ? !customerId.equals(customer.customerId) : customer.customerId != null) {
return false;
}
if(customerName != null ? !customerName.equals(customer.customerName) : customer.customerName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = customerId != null ? customerId.hashCode() : 0;
result = 31 * result + (customerName != null ? customerName.hashCode() : 0);
return result;
}
}

Customer.java

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-11-13:23
*/
public class Order {
private Integer orderId;
private String orderName; public Integer getOrderId() {
return orderId;
} public void setOrderId(Integer orderId) {
this.orderId = orderId;
} public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Order order = (Order) o; if(orderId != null ? !orderId.equals(order.orderId) : order.orderId != null) {
return false;
}
if(orderName != null ? !orderName.equals(order.orderName) : order.orderName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = orderId != null ? orderId.hashCode() : 0;
result = 31 * result + (orderName != null ? orderName.hashCode() : 0);
return result;
}
}

Order.java

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> <class name="com.nucsoft.hibernate.Customer" table="customer" schema="hibernate">
<id name="customerId">
<column name="customer_id" sql-type="int(11)"/>
</id>
<property name="customerName">
<column name="customer_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
</class>
</hibernate-mapping>

Customer.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> <class name="com.nucsoft.hibernate.Order" table="order" schema="hibernate">
<id name="orderId">
<column name="order_id" sql-type="int(11)"/>
</id>
<property name="orderName">
<column name="order_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
</class>
</hibernate-mapping>

Order.hbm.xml

<2>手动建立关联关系

①在 Order 一端建立多对一的关联关系。

  • 在 Order 持久化类中添加 Customer 类型的一个属性 customer。
  • 在 Order.hbm.xml 文件中添加多对一的关联关系。同时修改主键生成方式为 native。

②在 Customer 一端建立一对多的关联关系。

  • 在 Customer 持久化类中添加 Order 的一个集合 orders。
  • 在 Customer.hbm.xml 添加一对多的关联关系。同时修改主键生成方式为 native。

③详细说明:在 Customer.hbm.xml 文件中添加一对多的关联关系。

  • 当 Session 从数据库中加载 Java 集合时,创建的是 Hibernate 内置的集合类的实例。因此在持久化类中定义集合属性时需要定义成接口类型,不能是具体的某个实现类。

    • Hibernate 内置的集合具有集合代理功能,因为有代理功能,所以支持延迟检索策略。  
  • 在定义集合的时候,通常将其初始化为集合实现类的一个实例,防止 NullPointerException。
  • Hibernate 使用 <set> 元素来映射 Set 类型的属性。
  • 1 的一端的 Set 类型属性数据还是存放在 n 的一端。

④ set 元素

  • name 属性:待映射的 Set 类型的属性的属性名称。
  • table 属性:待映射的 Set 属性的泛型类型所对应的表。
  • key 子元素:column 属性,多的一端的外键名称。
  • one-to-many 子元素:class 属性,n 的一端的持久化类名称。

对应关系如图。

⑤最终的实体类和 Entity.hbm.xml 文件。

package com.nucsoft.hibernate;

import java.util.HashSet;
import java.util.Set; /**
* @author solverpeng
* @create 2016-10-11-13:23
*/
public class Customer {
private Integer customerId;
private String customerName; private Set<Order> orders = new HashSet<>(); public Set<Order> getOrders() {
return orders;
} public void setOrders(Set<Order> orders) {
this.orders = orders;
} public Integer getCustomerId() {
return customerId;
} public void setCustomerId(Integer customerId) {
this.customerId = customerId;
} public String getCustomerName() {
return customerName;
} public void setCustomerName(String customerName) {
this.customerName = customerName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Customer customer = (Customer) o; if(customerId != null ? !customerId.equals(customer.customerId) : customer.customerId != null) {
return false;
}
if(customerName != null ? !customerName.equals(customer.customerName) : customer.customerName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = customerId != null ? customerId.hashCode() : 0;
result = 31 * result + (customerName != null ? customerName.hashCode() : 0);
return result;
}
}

Customer.java

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-11-13:23
*/
public class Order {
private Integer orderId;
private String orderName; private Customer customer; public Customer getCustomer() {
return customer;
} public void setCustomer(Customer customer) {
this.customer = customer;
} public Integer getOrderId() {
return orderId;
} public void setOrderId(Integer orderId) {
this.orderId = orderId;
} public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Order order = (Order) o; if(orderId != null ? !orderId.equals(order.orderId) : order.orderId != null) {
return false;
}
if(orderName != null ? !orderName.equals(order.orderName) : order.orderName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = orderId != null ? orderId.hashCode() : 0;
result = 31 * result + (orderName != null ? orderName.hashCode() : 0);
return result;
}
}

Order.java

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.nucsoft.hibernate"> <class name="Customer" table="customer" schema="hibernate">
<id name="customerId">
<column name="customer_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="customerName">
<column name="customer_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
<set name="orders" table="order">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>

Customer.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.nucsoft.hibernate"> <class name="Order" table="order" schema="hibernate">
<id name="orderId">
<column name="order_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="orderName">
<column name="order_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
<many-to-one name="customer" class="Customer" column="customer_id"/>
</class>
</hibernate-mapping>

Order.hbm.xml

(4)通过 Intellij Idea 直接生成双向的多对一的关联关系。

<1>为生成的每个 Entity.hbm.xml 文件添加主键生成方式。

<2>为 Customer 类中的 orders 属性进行初始化。

<3>最终的持久化类和 Entity.hbm.xml。

package com.nucsoft.hibernate;

import java.util.HashSet;
import java.util.Set; /**
* @author solverpeng
* @create 2016-10-11-14:01
*/
public class Customer {
private Integer customerId;
private String customerName;
private Set<Order> orders = new HashSet<>(); public Integer getCustomerId() {
return customerId;
} public void setCustomerId(Integer customerId) {
this.customerId = customerId;
} public String getCustomerName() {
return customerName;
} public void setCustomerName(String customerName) {
this.customerName = customerName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Customer customer = (Customer) o; if(customerId != null ? !customerId.equals(customer.customerId) : customer.customerId != null) {
return false;
}
if(customerName != null ? !customerName.equals(customer.customerName) : customer.customerName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = customerId != null ? customerId.hashCode() : 0;
result = 31 * result + (customerName != null ? customerName.hashCode() : 0);
return result;
} public Set<Order> getOrders() {
return orders;
} public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}

Customer.java

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-11-14:01
*/
public class Order {
private Integer orderId;
private String orderName;
private Customer customer; public Integer getOrderId() {
return orderId;
} public void setOrderId(Integer orderId) {
this.orderId = orderId;
} public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Order order = (Order) o; if(orderId != null ? !orderId.equals(order.orderId) : order.orderId != null) {
return false;
}
if(orderName != null ? !orderName.equals(order.orderName) : order.orderName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = orderId != null ? orderId.hashCode() : 0;
result = 31 * result + (orderName != null ? orderName.hashCode() : 0);
return result;
} public Customer getCustomer() {
return customer;
} public void setCustomer(Customer customer) {
this.customer = customer;
}
}

Order.java

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> <class name="com.nucsoft.hibernate.Customer" table="customer" schema="hibernate">
<id name="customerId">
<column name="customer_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="customerName">
<column name="customer_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
<set name="orders" inverse="true">
<key>
<column name="customer_id" not-null="true"/>
</key>
<one-to-many not-found="ignore" class="com.nucsoft.hibernate.Order"/>
</set>
</class>
</hibernate-mapping>

Customer.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> <class name="com.nucsoft.hibernate.Order" table="order" schema="hibernate">
<id name="orderId">
<column name="order_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="orderName">
<column name="order_name" sql-type="varchar(50)" length="50" not-null="true"/>
</property>
<many-to-one name="customer" class="com.nucsoft.hibernate.Customer">
<column name="customer_id" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>

Order.hbm.xml

<4>对比发现,通过 Intellij Idea 自动生成的 Customer.hbm.xml 文件中 set 元素多了一个 inverse 属性。稍后进行说明。

(5)双向多对一的 CRUD 和需要注意的问题

<1>新增

①双方都维护关联关系,即没有设置 inverse 属性,且没有添加非空约束。

先保存 1 的一端,再保存 n 的一端。

@Test
public void testMany2OneBothSave() {
Customer customer = new Customer();
customer.setCustomerName("aa"); Order order = new Order();
order.setOrderName("order1");
order.setCustomer(customer); Order order2 = new Order();
order2.setOrderName("order2");
order2.setCustomer(customer); customer.getOrders().add(order);
customer.getOrders().add(order2); session.save(customer);
session.save(order);
session.save(order2); }

Save.java

打印SQL:

Hibernate:
insert
into
hibernate.customer
(customer_name)
values
(?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
update
hibernate.order
set
customer_id=?
where
order_id=?
Hibernate:
update
hibernate.order
set
customer_id=?
where
order_id=?

Output

结果:打印了 3 条 INSERT 语句,2 条 UPDATE 语句

先保存 n 的一端,再保存 1 的一端。

@Test
public void testMany2OneBothSave() {
Customer customer = new Customer();
customer.setCustomerName("cc"); Order order = new Order();
order.setOrderName("order5");
order.setCustomer(customer); Order order2 = new Order();
order2.setOrderName("order6");
order2.setCustomer(customer); customer.getOrders().add(order);
customer.getOrders().add(order2); session.save(order);
session.save(order2);
session.save(customer);
}

Save2.java

打印 SQL :

Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.customer
(customer_name)
values
(?)
Hibernate:
update
hibernate.order
set
order_name=?,
customer_id=?
where
order_id=?
Hibernate:
update
hibernate.order
set
order_name=?,
customer_id=?
where
order_id=?
Hibernate:
update
hibernate.order
set
customer_id=?
where
order_id=?
Hibernate:
update
hibernate.order
set
customer_id=?
where
order_id=?

Output2

结果:打印了 3 条 INSERT 语句,4 条 UPDATE 语句。原因,双方都维护这关联关系。

②双方都维护关联关系,即没有设置 inverse 属性,对 order 表中的 customer_id 列添加非空约束(需要更改两个地方)。

先保存 n 的一端,再保存 1 的一端,会抛出异常。

org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : com.nucsoft.hibernate.Order.customer -> com.nucsoft.hibernate.Customer

③ 1 的一端放弃维护关联关系,只由 n 的一端来维护。即设置 Customer.hbm.xml 的 set 元素 inverse 属性值为 true。

先保存 1 的一端,后保存 n 的一端。

Hibernate:
insert
into
hibernate.customer
(customer_name)
values
(?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.order
(order_name, customer_id)
values
(?, ?)

Output

结果:只会发送3条 INSERT 语句。

④总结:

介绍了双向的多对一的下的保存操作,若都维护关联关系,则会多出 UPDATE 语句。且若外键存在非空约束时,不能先保存 n 的一端。

所以在进行 Hibernate 双向多对一保存的时候,最好的做法就是:

1 的一端放弃维护关联关系,即 设置 set 节点的 inverse 属性为  true。同时在保存的时候先保存 1 的一端,后保存 n 的一端。

<2>删除

@Test
public void testMany2OneBothDelete() {
Customer customer = (Customer) session.get(Customer.class, 5);
session.delete(customer);
}

Delete

同删除单向的多对一相同,会抛出异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails

存在外键约束。

<3>更新

@Test
public void testMany2OneBothUpdate() {
Customer customer = (Customer) session.get(Customer.class, 5);
System.out.println(customer.getOrders().iterator().next().getOrderName());
customer.getOrders().iterator().next().setOrderName("order@@");
}

Update

Hibernate:
select
customer0_.customer_id as customer1_0_0_,
customer0_.customer_name as customer2_0_0_
from
hibernate.customer customer0_
where
customer0_.customer_id=?
Hibernate:
select
orders0_.customer_id as customer3_0_0_,
orders0_.order_id as order_id1_1_0_,
orders0_.order_id as order_id1_1_1_,
orders0_.order_name as order_na2_1_1_,
orders0_.customer_id as customer3_1_1_
from
hibernate.order orders0_
where
orders0_.customer_id=?
order4
Hibernate:
update
hibernate.order
set
order_name=?,
customer_id=?
where
order_id=?

Output

<4>查询

@Test
public void testMany2OneBothGet() {
Customer customer = (Customer) session.get(Customer.class, 5);
System.out.println(customer.getOrders().getClass());
}

打印结果:

Hibernate:
select
customer0_.customer_id as customer1_0_0_,
customer0_.customer_name as customer2_0_0_
from
hibernate.customer customer0_
where
customer0_.customer_id=?
class org.hibernate.collection.internal.PersistentSet

并没有查询关联的 Order 集合,实际类型为 Hibernate 内置的一个 Set 实现类。

证明了:

当 Session 从数据库中加载 Java 集合时,创建的是 Hibernate 内置的集合类的实例。因此在持久化类中定义集合属性时需要定义成接口类型,不能是具体的某个实现类。

也证明了:

Hibernate 内置的集合具有集合代理功能,因为有代理功能,所以支持延迟检索策略。

<5>说明

这里没有介绍 cascade 属性,是因为在实际的项目中,为了保护数据,很少设置 cascade 属性,而是手动去处理。

二、映射一对一关联关系。

1.这里只介绍双向的一对一关联关系如何映射。单向的一对一只需要把没有外键的一端去掉就好了。

2.基于外键映射的双向一对一

(1)以 Dempartment 和 Manager 为例。一个部门只能有一个经理,一个经理职能管理一个部门。

(2)创建 Department 和 Manager 表。在 Department 表建立 Manager 表的外键。

CREATE TABLE department
(
dept_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
dept_name VARCHAR(50),
manager_id_fk INT(11)
);

department.sql

CREATE TABLE manager
(
manager_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
manager_name VARCHAR(50)
);

Manager.xml

(3)通过 Intellij Idea 自动生成的双向 1 对 1 无法映射列。这里通过 Intellij Idea 生成简单的持久化类和 Entity.hbm.xml 文件,然后手动的添加映射。

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-12-9:59
*/
public class Department {
private Integer deptId;
private String deptName;
private Manager manager; public Integer getDeptId() {
return deptId;
} public void setDeptId(Integer deptId) {
this.deptId = deptId;
} public String getDeptName() {
return deptName;
} public void setDeptName(String deptName) {
this.deptName = deptName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Department that = (Department) o; if(deptId != null ? !deptId.equals(that.deptId) : that.deptId != null) {
return false;
}
if(deptName != null ? !deptName.equals(that.deptName) : that.deptName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = deptId != null ? deptId.hashCode() : 0;
result = 31 * result + (deptName != null ? deptName.hashCode() : 0);
return result;
} public Manager getManager() {
return manager;
} public void setManager(Manager manager) {
this.manager = manager;
}
}

Department.java

package com.nucsoft.hibernate;

/**
* @author solverpeng
* @create 2016-10-12-9:59
*/
public class Manager {
private Integer managerId;
private String managerName;
private Department dept; public Integer getManagerId() {
return managerId;
} public void setManagerId(Integer managerId) {
this.managerId = managerId;
} public String getManagerName() {
return managerName;
} public void setManagerName(String managerName) {
this.managerName = managerName;
} @Override
public boolean equals(Object o) {
if(this == o) {
return true;
}
if(o == null || getClass() != o.getClass()) {
return false;
} Manager manager = (Manager) o; if(managerId != null ? !managerId.equals(manager.managerId) : manager.managerId != null) {
return false;
}
if(managerName != null ? !managerName.equals(manager.managerName) : manager.managerName != null) {
return false;
} return true;
} @Override
public int hashCode() {
int result = managerId != null ? managerId.hashCode() : 0;
result = 31 * result + (managerName != null ? managerName.hashCode() : 0);
return result;
} public Department getDept() {
return dept;
} public void setDept(Department dept) {
this.dept = dept;
}
}

Manager.java

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.nucsoft.hibernate.Department" table="department" schema="hibernate">
<id name="deptId" column="dept_id">
<generator class="native"/>
</id>
<property name="deptName" column="dept_name"/>
<many-to-one name="manager" class="com.nucsoft.hibernate.Manager" column="manager_id_fk" unique="true"/>
</class>
</hibernate-mapping>

Department.hbm.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping> <class name="com.nucsoft.hibernate.Manager" table="manager" schema="hibernate">
<id name="managerId" column="manager_id">
<generator class="native"/>
</id>
<property name="managerName" column="manager_name"/>
<one-to-one name="dept" class="com.nucsoft.hibernate.Department" property-ref="manager"/>
</class>
</hibernate-mapping>

Manager.hbm.xml

(4)说明:

在 department  表中来维护外键。在映射的时候选择 <many-to-one > 元素,通过 unique 属性来达到 一对一的效果。

在 manager 表中没有维护外键。在映射时候选择 <one-to-one>元素,至于属性 property-ref 稍后在查询的时候说明。

(5)CRUD 以及需要注意的地方。

<1>save

@Test
public void testSave() {
Department department = new Department();
department.setDeptName("dept-4"); Manager manager = new Manager();
manager.setManagerName("manager=DD"); department.setManager(manager);
manager.setDept(department); session.save(manager);
session.save(department);
}

Save1.java

Hibernate:
insert
into
hibernate.manager
(manager_name)
values
(?)
Hibernate:
insert
into
hibernate.department
(dept_name, manager_id_fk)
values
(?, ?)

Output1

@Test
public void testSave() {
Department department = new Department(); department.setDeptName("dept-2"); Manager manager = new Manager();
manager.setManagerName("manager=BB"); department.setManager(manager);
manager.setDept(department); session.save(department);
session.save(manager);
}

Save2.java

Hibernate:
insert
into
hibernate.department
(dept_name, manager_id_fk)
values
(?, ?)
Hibernate:
insert
into
hibernate.manager
(manager_name)
values
(?)
Hibernate:
update
hibernate.department
set
dept_name=?,
manager_id_fk=?
where
dept_id=?

Output2

对比发现,先保存没有外键列的对象,会减少 UPDATE 语句的发送,提高性能。

<2>delete

@Test
public void testDelete() {
Department department = (Department) session.get(Department.class, 4);
session.delete(department);
}

Delete1.java

Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_,
department0_.manager_id_fk as manager3_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
Hibernate:
delete
from
hibernate.department
where
dept_id=?

Output1

@Test
public void testDelete() {
Manager manager = (Manager) session.get(Manager.class, 5);
session.delete(manager);
}

Delete2.java

Cannot delete or update a parent row: a foreign key constraint fails (`hibernate`.`department`, CONSTRAINT `FK_kpcmf8csabfn9epikikcfqbk0` FOREIGN KEY (`manager_id_fk`) REFERENCES `manager` (`manager_id`))

外键关联对象存在的情况下,不能先删除拥有外键的对象。

<3>update

@Test
public void testUpdate() {
Department department = (Department) session.get(Department.class, 6);
department.getManager().setManagerName("@@");
}

Update.java

Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_,
department0_.manager_id_fk as manager3_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_,
department1_.manager_id_fk as manager3_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?
Hibernate:
update
hibernate.manager
set
manager_name=?
where
manager_id=?

Output

<4>get

@Test
public void testGet() {
Department department = (Department) session.get(Department.class, 6);
System.out.println(department); System.out.println(department.getManager().getClass()); System.out.println("---------------");
System.out.println(department.getManager().getManagerName()); }

Get1.java

Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_,
department0_.manager_id_fk as manager3_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
com.nucsoft.hibernate.Department@b0688765
class com.nucsoft.hibernate.Manager_$$_javassist_1
---------------
Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_,
department1_.manager_id_fk as manager3_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?
@@

Output1

可以看到, 查询拥有外键对象关联的对象时,采用的还是懒加载机制。此种情况下,若 session 关闭,再去调用关联对象的某个属性,会发生懒加载异常。

查询双向一对一中没有外键的一端:

<one-to-one name="dept" class="com.nucsoft.hibernate.Department"/>

@Test
public void testGet2() {
Manager manager = (Manager) session.get(Manager.class, 6);
System.out.println(manager);
}

Get2.java

Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_,
department1_.manager_id_fk as manager3_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?
com.nucsoft.hibernate.Manager@8ba

<one-to-one name="dept" class="com.nucsoft.hibernate.Department" property-ref="manager"/>

Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_,
department1_.manager_id_fk as manager3_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.manager_id_fk
where
manager0_.manager_id=?
com.nucsoft.hibernate.Manager@8ba

可以发现,在第一次查询时,没有设置 property-ref 属性。左外链接查询时,虽然结果正确,但是连接条件不正确。

至于说,为什么查询 Manager 对象的时候,使用了左外链接而不是懒加载,因为 Manager 端没有 Deparment 的外键。它不知道谁与它有关系。只能通过左外链接查询一次查询。

3.基于主键的双向的一对一

(1)本质上和基于外键的双向一对一关联一样,只不过是以主键作为了外键来使用的。

(2)还是以 Department 和 Manager 为例。

(3)deparment 表做了改动,因为是基于主键的映射,这里将 department 表中 manager_id_fk 去掉了。

(4)Department.hbm.xml 和 Manager.hbm.xml 文件

<hibernate-mapping>
<class name="com.nucsoft.hibernate.Department" table="department" schema="hibernate">
<id name="deptId" column="dept_id">
<generator class="foreign">
<param name="property">manager</param>
</generator>
</id>
<property name="deptName" column="dept_name"/>
<one-to-one name="manager" class="com.nucsoft.hibernate.Manager" constrained="true"/>
</class>
</hibernate-mapping>

对于 Department.hbm.xml 文件,主键生成方式改为 foreign,并且指定了主键生成所依赖的属性所对应的持久化类的主键生成方式。

需要注意的是,需要在 <one-to-one>节点添加 constrained 属性为true。

<hibernate-mapping>
<class name="com.nucsoft.hibernate.Manager" table="manager" schema="hibernate">
<id name="managerId" column="manager_id">
<generator class="native"/>
</id>
<property name="managerName" column="manager_name"/>
<one-to-one name="dept" class="com.nucsoft.hibernate.Department"/>
</class>
</hibernate-mapping>

将 Manager.hbm.xml 文件的 <one-to-one> 节点的 property-ref 属性去掉了。

(5)CRUD及需要注意的问题

<1>save

@Test
public void testSave() {
Department department = new Department();
department.setDeptName("dept=1"); Manager manager = new Manager();
manager.setManagerName("manager-1"); manager.setDept(department);
department.setManager(manager); session.save(manager);
session.save(department);
}

Save1.java

@Test
public void testSave() {
Department department = new Department();
department.setDeptName("dept=2"); Manager manager = new Manager();
manager.setManagerName("manager-2"); manager.setDept(department);
department.setManager(manager); session.save(department);
session.save(manager);
}

Save2.java

Hibernate:
insert
into
hibernate.manager
(manager_name)
values
(?)
Hibernate:
insert
into
hibernate.department
(dept_name, dept_id)
values
(?, ?)

Output

结论:

发现不论是先保存 department ,还是先保存 manager,都是先插入的 manager。因为 department 的主键生成方式是依赖于 manager 的。

<2>update

@Test
public void testUpdate() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getManager().getManagerName());
department.getManager().setManagerName("@@");
}

Update.java

Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?
manager-1
Hibernate:
update
hibernate.manager
set
manager_name=?
where
manager_id=?

Output

@Test
public void testUpdate() {
Manager manager = (Manager) session.get(Manager.class, 1);
System.out.println(manager.getDept().getDeptName());
manager.getDept().setDeptName("@@Dept");
}

Update2.java

Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?
dept=1
Hibernate:
update
hibernate.department
set
dept_name=?
where
dept_id=?

Output2

<3>get

@Test
public void testGet() {
Department department = (Department) session.get(Department.class, 1);
System.out.println(department.getManager().getClass());
System.out.println("--------------------------------------");
Manager manager = (Manager) session.get(Manager.class, 1);
}

Get.java

Hibernate:
select
department0_.dept_id as dept1_0_0_,
department0_.dept_name as dept2_0_0_
from
hibernate.department department0_
where
department0_.dept_id=?
class com.nucsoft.hibernate.Manager_$$_javassist_1
--------------------------------------
Hibernate:
select
manager0_.manager_id as manager1_1_1_,
manager0_.manager_name as manager2_1_1_,
department1_.dept_id as dept1_0_0_,
department1_.dept_name as dept2_0_0_
from
hibernate.manager manager0_
left outer join
hibernate.department department1_
on manager0_.manager_id=department1_.dept_id
where
manager0_.manager_id=?

Output

通过 department 获取到的 manager 采用的是懒加载机制。而从 manager 获取 dept ,是通过左外链接查询的。

至于原因,第一小点已经提到,本质上和基于外键的双向一对一关联一样,只不过是以主键作为了外键来使用的。

<4>delete

@Test
public void testDelete() {
Manager manager = (Manager) session.get(Manager.class, 1);
session.delete(manager);
}

Delete.java

Cannot delete or update a parent row: a foreign key constraint fails (`hibernate`.`department`, CONSTRAINT `FK_8hf3vewo7w3v9doungcc51wwy` FOREIGN KEY (`dept_id`) REFERENCES `manager` (`manager_id`))

若先删除 manager ,且存在和此 manager 关联的 department ,需要先删除关联的 department 记录。

三、映射 n 对 n 关联关系

1.单向的 n 对 n 关联

(1)必须使用中间表

(2)以 Category 和 Item 为例。一个分类下可以有多个商品,一个商品可以属于多个分类。以 Category 下存在 Set<Item> 集合为例来测试单向的 n 对 n 映射。

(3)创建 category、item、categories_items 表

CREATE TABLE category (
category_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
category_name VARCHAR(50)
); CREATE TABLE item (
item_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
item_name VARCHAR(50)
); CREATE TABLE categories_items (
category_id INT(11) NOT NULL,
item_id INT(11) NOT NULL
);

Sql

(4)通过 Intellij Idea 生成持久化类和 Entity.hbm.xml 文件

生成的持久化类和 Category.hbm.xml 和 Item.hbm.xml 文件。

public class Category {
private Integer categoryId;
private String categoryName;
private Set<Item> items;
}

Category.java

public class Item {
private Integer itemId;
private String itemName;
}

Item.java

<hibernate-mapping>
<class name="com.nucsoft.hibernate.Item" table="item" schema="hibernate">
<id name="itemId" column="item_id">
<generator class="native"/>
</id>
<property name="itemName" column="item_name"/>
</class>
</hibernate-mapping>

Item.hbm.xml

<hibernate-mapping>
<class name="com.nucsoft.hibernate.Category" table="category" schema="hibernate">
<id name="categoryId" column="category_id">
<generator class="native"/>
</id>
<property name="categoryName" column="category_name"/>
<!-- table 指中间表 -->
<set name="items" table="categories_items" schema="hibernate">
<key>
<!-- category 在中间表中的列名 -->
<column name="category_id"/>
</key>
<!-- class Set 集合中持久化类的类名, column Set集合中的持久化类咋中间表的外键列的名称 -->
<many-to-many not-found="ignore" class="com.nucsoft.hibernate.Item">
<column name="item_id"/>
</many-to-many>
</set>
</class>
</hibernate-mapping>

注释已经讲的很明白了。

(5)CRUD 以及需要注意的地方。

<1>save

@Test
public void testSave() {
Item item = new Item();
item.setItemName("item-aa");
Item item2 = new Item();
item2.setItemName("item-bb"); Category category = new Category();
category.setCategoryName("cate-1");
category.getItems().add(item);
category.getItems().add(item2); session.save(item);
session.save(item2);
session.save(category);
}

Save1.java

Hibernate:
insert
into
hibernate.item
(item_name)
values
(?)
Hibernate:
insert
into
hibernate.item
(item_name)
values
(?)
Hibernate:
insert
into
hibernate.category
(category_name)
values
(?)
Hibernate:
insert
into
hibernate.categories_items
(category_id, item_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.categories_items
(category_id, item_id)
values
(?, ?)

Output1

@Test
public void testSave() {
Item item = new Item();
item.setItemName("item-cc");
Item item2 = new Item();
item2.setItemName("item-dd"); Category category = new Category();
category.setCategoryName("cate-2");
category.getItems().add(item);
category.getItems().add(item2); session.save(category);
session.save(item);
session.save(item2);
}

Save2.java

Hibernate:
insert
into
hibernate.category
(category_name)
values
(?)
Hibernate:
insert
into
hibernate.item
(item_name)
values
(?)
Hibernate:
insert
into
hibernate.item
(item_name)
values
(?)
Hibernate:
insert
into
hibernate.categories_items
(category_id, item_id)
values
(?, ?)
Hibernate:
insert
into
hibernate.categories_items
(category_id, item_id)
values
(?, ?)

Output2

结论:

对比发现,不论是先保存 Item 还是先保存 Category 对象,都不会多发送 UPDATE 语句,因为最终的关联关系是通过中间表进行维护的。

<2>get

@Test
public void testGet() {
Category category = (Category) session.get(Category.class, 1);
System.out.println(category.getItems().getClass());
System.out.println(category.getItems().size());
}

Get.java

Hibernate:
select
category0_.category_id as category1_1_0_,
category0_.category_name as category2_1_0_
from
hibernate.category category0_
where
category0_.category_id=?
class org.hibernate.collection.internal.PersistentSet
Hibernate:
select
items0_.category_id as category1_1_1_,
items0_.item_id as item2_0_1_,
item1_.item_id as item1_2_0_,
item1_.item_name as item2_2_0_
from
hibernate.categories_items items0_
inner join
hibernate.item item1_
on items0_.item_id=item1_.item_id
where
items0_.category_id=?
2

Output

还是懒加载,但是查询关联的 Items 的时候,内连接关联了中间表。

<3>delete

@Test
public void testDelete() {
Category category = (Category) session.get(Category.class, 1);
session.delete(category);
}

Delete1.java

Hibernate:
select
category0_.category_id as category1_1_0_,
category0_.category_name as category2_1_0_
from
hibernate.category category0_
where
category0_.category_id=?
Hibernate:
delete
from
hibernate.categories_items
where
category_id=?
Hibernate:
delete
from
hibernate.category
where
category_id=?

删除 category 的时候,先删除的中间表,然后才删除的 category表。表明,先解除关系,然后删除。

@Test
public void testDelete2() {
Item item = (Item) session.get(Item.class, 4);
session.delete(item);
}

Delete2.java

Cannot delete or update a parent row: a foreign key constraint fails (`hibernate`.`categories_items`, CONSTRAINT `FK_pxxtlg5rb8it8ewp5lxhss3c5` FOREIGN KEY (`item_id`) REFERENCES `item` (`item_id`))

删除 item 时,因为有关联关系的存在,且维护关联关系是由 Category 维护的,所以无法删除。

2.映射双向的 n 对 n

(1)还以 Category 和 Item 为例。Category 中拥有 Set<Item> 类型的属性, Item 中拥有 Set<Category> 类型的属性。

(2)通过 Intellij Idea 生成持久化类和 Entity.hbm.xml 文件。

对应生成的文件:

public class Category {
private Integer categoryId;
private String categoryName;
private Set<Item> items;
}

Category.java

public class Item {
private Integer itemId;
private String itemName;
private Set<Category> categories;
}

Item.java

<hibernate-mapping package="com.nucsoft.hibernate" schema="hibernate">
<class name="Item" table="item">
<id name="itemId" column="item_id">
<generator class="native"/>
</id>
<property name="itemName" column="item_name"/>
<set name="categories" inverse="true" table="categories_items">
<key>
<column name="item_id"/>
</key>
<!-- 交叉对应 -->
<many-to-many not-found="ignore" class="Category">
<column name="category_id"/>
</many-to-many>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping package="com.nucsoft.hibernate" schema="hibernate">
<class name="Category" table="category">
<id name="categoryId" column="category_id">
<generator class="native"/>
</id>
<property name="categoryName" column="category_name"/>
<set name="items" table="categories_items">
<key>
<column name="category_id"/>
</key>
<!-- 交叉对应 -->
<many-to-many not-found="ignore" class="Item">
<column name="item_id"/>
</many-to-many>
</set>
</class>
</hibernate-mapping>

(3)注意:

  • 需要两端都使用集合属性
  • 必须使用中间表
  • 两边都需要指定中间表表名以及在中间表中外键列的列名。
  • 必须把其中一端 的 inverse 属性设置为 true

四、总结

介绍了Hibernate如何映射 单双向的多对一,基于外键、基于主键的一对一,以及单双向的多对多的关联关系。包括在 Intellij Idea下如何操作,以及各个类型映射下的 CRUR 以及需要注意的地方。

没有介绍 Hibernate 是如何映射继承关系,是因为在真实的生产环境下还没有遇到这种情况,这里不做说明。

文章篇幅较长,所以摘录了一个附录出来,以便查询方便。http://www.cnblogs.com/solverpeng/p/5953536.html

写文章不易,若转载,请标明出处。

注意:每次通过 Intellij Idea 的 Database Schema 生成 Entity.hbm.xml 和持久化类的时候,都会覆盖数据库连接的 username 和 password 。需要重新添加。

Hibernate —— 映射关联关系的更多相关文章

  1. Hibernate —— 映射关联关系(附录)

    一.单向的多对一 1.建表语句 CREATE TABLE customer ( customer_id ) NOT NULL AUTO_INCREMENT PRIMARY KEY , ) CREATE ...

  2. hibernate映射的 关联关系:有 一对多关联关系,一对一关联关系,多对多关联关系,继承关系

    hibernate环境配置:导包.... 单向n-1:单向 n-1 关联只需从 n 的一端可以访问 1 的一端 <many-to-one> 元素来映射组成关系: name: 设定待映射的持 ...

  3. Hibernate之关联关系映射(一对一主键映射和一对一外键映射)

    1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信 ...

  4. 框架之 hibernate之关联关系映射

    案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...

  5. Hibernate的关联关系映射

    技术分析之Hibernate的关联关系映射之一对多映射(重点)        1. JavaWEB中一对多的设计及其建表原则        2. 先导入SQL的建表语句                 ...

  6. 02.Hibernate映射基础

    前言:Hibernate的核心功能是根据数据库到实体类的映射,自动从数据库绑定数据到实体类.使我们操作实体类(Java对象)就能对数据库进行增.删.查.改,而不用调用JDBC API使数据操作变得简单 ...

  7. [转]Hibernate映射的基本操作

       ++YONG原创,转载请注明http://blog.csdn.net/qjyong/article/details/1829672          Hibernate映射主要是通过对象关系映射 ...

  8. 【SSH系列】Hibernate映射 -- 一对多关联映射

        映射原理       一对多关联映射和多对一关联映射的映射原理是一样一样的,所以说嘛,知识都是相通的,一通百通,为什么说一对多关联映射和多对一关联映射是一样的呢?因为她们都是在多的一端加入一个 ...

  9. JPA(六):映射关联关系------映射单向一对多的关联关系

    映射单向一对多的关联关系 新建项目项目请参考<JPA(二):HellWord工程>,基于上一章讲解的<JPA(五):映射关联关系------映射单向多对一的关联关系>中的例子进 ...

随机推荐

  1. RFID工作流程

    读写器通过发射天线发送一定频率的射频信号,² 当射频卡进入发射天线工作区域时产生感应电²流,射频卡获得能量被启动.²²射频卡将自身编码等信息透过卡内天线发送出²去.²²读写器接收天线接收到从 射频卡发 ...

  2. HTML打折计算价格

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <met ...

  3. ASP.NET跨平台实践:无需安装Mono的Jexus“独立版”

    在Linux上运行ASP.NET网站或WebApi的传统步骤是,先安装libgdiplus,再安装mono,然后安装Jexus.在这个过程中,虽然安装Jexus是挺简便的一件事,但是安装mono就相对 ...

  4. .NET Core 跨平台发布(dotnet publish)

    .NET Core 跨平台发布(dotnet publish) ,无需安装.NET Core SDK,就可以运行. 前面讲解了.NET Core 的VSCode 开发.现在来讲讲发布(dotnet p ...

  5. 领域驱动设计(DDD)部分核心概念的个人理解

    领域驱动设计(DDD)是一种基于模型驱动的软件设计方式.它以领域为核心,分析领域中的问题,通过建立一个领域模型来有效的解决领域中的核心的复杂问题.Eric Ivans为领域驱动设计提出了大量的最佳实践 ...

  6. Python黑帽编程 3.1 ARP欺骗

    Python灰帽编程 3.1 ARP欺骗 ARP欺骗是一种在局域网中常用的攻击手段,目的是让局域网中指定的(或全部)的目标机器的数据包都通过攻击者主机进行转发,是实现中间人攻击的常用手段,从而实现数据 ...

  7. 我的LESS编译方案

    背景 近期项目前端决定使用less,简单介绍一下,详细信息有兴趣查看官方文档(http://www.lesscss.net/article/home.html) LESSCSS是一种动态样式语言,属于 ...

  8. 我心中的核心组件(可插拔的AOP)~大话开篇及目录

    回到占占推荐博客索引 核心组件 我心中的核心组件,核心组件就是我认为在项目中比较常用的功能,如日志,异常处理,消息,邮件,队列服务,调度,缓存,持久化,分布式文件存储,NoSQL存储,IoC容器,方法 ...

  9. Hadoop HDFS 用户指南

    This document is a starting point for users working with Hadoop Distributed File System (HDFS) eithe ...

  10. Android开发学习之路-带文字的图片分享

    有用过微信分享SDK的都应该知道,微信分享到朋友圈的时候是不能同时分享图片和文字的,只要有缩略图,那么文字就不会生效.那么问题就来了,如果我们想把APP内的某些内容连带图片一起分享到微信,是不是没办法 ...