Hibernate —— 映射关联关系
一、映射多对一关联关系。
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 —— 映射关联关系的更多相关文章
- Hibernate —— 映射关联关系(附录)
一.单向的多对一 1.建表语句 CREATE TABLE customer ( customer_id ) NOT NULL AUTO_INCREMENT PRIMARY KEY , ) CREATE ...
- hibernate映射的 关联关系:有 一对多关联关系,一对一关联关系,多对多关联关系,继承关系
hibernate环境配置:导包.... 单向n-1:单向 n-1 关联只需从 n 的一端可以访问 1 的一端 <many-to-one> 元素来映射组成关系: name: 设定待映射的持 ...
- Hibernate之关联关系映射(一对一主键映射和一对一外键映射)
1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信 ...
- 框架之 hibernate之关联关系映射
案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...
- Hibernate的关联关系映射
技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. JavaWEB中一对多的设计及其建表原则 2. 先导入SQL的建表语句 ...
- 02.Hibernate映射基础
前言:Hibernate的核心功能是根据数据库到实体类的映射,自动从数据库绑定数据到实体类.使我们操作实体类(Java对象)就能对数据库进行增.删.查.改,而不用调用JDBC API使数据操作变得简单 ...
- [转]Hibernate映射的基本操作
++YONG原创,转载请注明http://blog.csdn.net/qjyong/article/details/1829672 Hibernate映射主要是通过对象关系映射 ...
- 【SSH系列】Hibernate映射 -- 一对多关联映射
映射原理 一对多关联映射和多对一关联映射的映射原理是一样一样的,所以说嘛,知识都是相通的,一通百通,为什么说一对多关联映射和多对一关联映射是一样的呢?因为她们都是在多的一端加入一个 ...
- JPA(六):映射关联关系------映射单向一对多的关联关系
映射单向一对多的关联关系 新建项目项目请参考<JPA(二):HellWord工程>,基于上一章讲解的<JPA(五):映射关联关系------映射单向多对一的关联关系>中的例子进 ...
随机推荐
- composer安装
1.首先到php.net下载对应版本的php,zip版本即可,注意windows需要vc11运行库支持 2.配置path路径添加对php解压目录的引用 3.将php.ini-development ...
- WDM驱动加载方式理解
当PC得知有新设备插入时,总线驱动会创建相应的物理驱动PDO,然后提示有新设备插入,这时候调用相应Driver的AddDevice方法创建功能驱动FDO 下面是一个典型的AddDevice方法 #pr ...
- Call for Papers IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM)
IEEE/ACM International Conference on Advances in Social Network Analysis and Mining (ASONAM) 2014 In ...
- Expert 诊断优化系列------------------语句调优三板斧
前面三篇通过CPU.内存.磁盘三巨头,讲述了如何透过现在看本质,怎样定位服务器三巨头反映出的问题.为了方便阅读给出链接: SQL SERVER全面优化-------Expert for SQL Ser ...
- 作业六:团队项目——编写项目的Spec
主要内容: 各组结合所选项目,编写项目的规格说明书(Spec),Spec应至少包含以下内容:(20分) 1. Spec的目标 2. 项目的典型用户和场景 3. 项目的用例模型 4. 项目中涉及到的术语 ...
- Redis高可用分布式内部交流(九)
这是上月在公司内部的一次分享,现把PPT及交流内容整理成博客. 阅读目录: 高可用 数据同步 分布式 分布式集群时代 总结 高可用 高可用(High Availability),是当一台服务器停止服务 ...
- 女生的最爱,装饰品。WPF也有,Adorner。(上海晒衣服理念)
说到装饰,不由要说到女性. 去年过年回家给我妈买了周大福项链,很明显就感觉待遇就不一样了,即使这样,还是被一个阿姨说应该买更重点的.看来钱这种东西果然是多一点才好.虽然自己无所谓,但让家里人更开心也是 ...
- 几个常用Json组件的性能测试
上一篇文章中我已经介绍了JsonBuilder方案的整体思路以及一个版本的雏形代码,他现在已经是可以使用的了,但是因为是实时反射的,所以效率并不高. 鉴于几位博友对Json转换组件的性能有兴趣,我先放 ...
- 花一分钟来看看Worktile是如何为团队协作而生的
团队协作,我们想的更深.更远.更多,花一分钟来看看我们特别奉献的故事,然后去注册一个账号,邀请小伙伴一起来工作,你会体会Worktile才是真正懂你的协作方式.
- Html5绘制时钟
最近在对Html5比较感兴趣,就用空闲时间做一些小例子进行练习,今天绘制一个走动的时钟,具体如下图所示: 具体思路在上图已有说明,代码如下: <script type="text/ja ...