上一篇介绍了Hibernate的单向一对多关系,接下来用代码实例介绍一下自己在学习过程中的双向一对多关系映射。
先对一下的实例做一个总结:
一)双向一对多关系【客户 vs 订单】
(1)传统:保存1个客户,级联增加2个订单,设置双向关联,共5条SQL
在双向关联的情况下,双方都去维护之间的关系
当双方都去维护之间的关系,可能产生如下二种现象:
( A)无严重的错误,只是SQL产生过多
(B)有严重的错误,相同的主健冲突
(2)优化:保存1个客户,级联增加2个订单,设置双向关联,共3条SQL
在Customer单方配置了一个inverse=true属性,即让Order多方来维护SQL
(3)什么情况下用cascade(none默认/save-update/delete/all)和inverse(false默认/true)属性
inverse=false表示双方共同维护之间的关系,
inverse=true表示,由对方来维护之间的关系,
例如:inverse=true配置在单方,即由多方来维护之间的关系
例如:inverse=true配置在多方,即由单方来维护之间的关系
以情况下需要用到inverse=true属性
(A)【双】向一对【多】情况
(B)【双】向多对【多】情况
当操作Customer对象时,同时也要以相同的操作Order对象,此时可以使用cascade属性。
mysql数据库表的创建参考Hibernate进阶之单向一对多关系映射。
(1)传统:保存1个客户,级联增加2个订单,设置双向关联,共5条SQL。
映射文件CustomerOrder.hbm.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.many2one_double">
<class name="Customer" table="customers">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="name" column="name" type="string"></property>
<property name="age" column="age" type="int"></property>
<!-- set标签用于映射单向一对多
name表示单方的关联属性
table表示多方对应表的名字
key-cloumn表示多方对应表的外键
one-to-many-class表示单方关联属性中的每个元素的类型
-->
<set name="orderSet" table="orders" cascade="all">
<key column="customers_id"></key>
<one-to-many class="Order"/>
</set>
</class>
<!-- 映射类的多方 -->
<class name="Order" table="Orders">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="orderNo" column="orderNo"></property>
<property name="price" column="price"></property>
<many-to-one name="customer" column="customers_id"></many-to-one>
</class>
</hibernate-mapping>
实体类:Customer,Order类。
Customer类如下:
package example.many2one_double;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 客户(一方)
* @author Administrator
*
*/
public class Customer {
private Integer id;//对应表的主键
private String name;
private Integer age;
private Set<Order> orderSet=new LinkedHashSet<Order>();//关联属性
public Customer() {
}
public Customer(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Set<Order> getOrderSet() {
return orderSet;
}
public void setOrderSet(Set<Order> orderSet) {
this.orderSet = orderSet;
}
}
Order类如下:
package example.many2one_double;
/**
* 订单(多的一方)
* @author Administrator
*
*/
public class Order {
private Integer id;
private String OrderNo;//订单编号
private Integer price;//价格
private Customer customer;//关联的属性
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrderNo() {
return OrderNo;
}
public void setOrderNo(String orderNo) {
OrderNo = orderNo;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Order(String orderNo, Integer price) {
super();
OrderNo = orderNo;
this.price = price;
}
public Order() {
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
代码如下:
/**
* 保存1个客户,级联增加2个订单,设置双向关联,共5条SQL
*/
@Test
public void test01(){
Customer customer=new Customer("牛人",23);
Order o1=new Order("编号40001",350);
Order o2=new Order("编号40002",450);
//设置双向关联
customer.getOrderSet().add(o1);
customer.getOrderSet().add(o2);
o1.setCustomer(customer);
o2.setCustomer(customer);
Session session=HibernateUtils.getSession();
Transaction t=session.getTransaction();
try{
t.begin();
session.save(customer);
t.commit();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
t.rollback();
}finally{
HibernateUtils.closeSession();
}
}
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into customers (name, age) values (?, ?)
Hibernate: insert into Orders (orderNo, price, customers_id) values (?, ?, ?)
Hibernate: insert into Orders (orderNo, price, customers_id) values (?, ?, ?)
Hibernate: update Orders set customers_id=? where id=?
Hibernate: update Orders set customers_id=? where id=?
第二种:优化:保存1个客户,级联增加2个订单,设置双向关联,共3条SQL,在Customer单方配置了一个inverse=true属性,即让Order多方来维护SQL。
修改映射文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.many2one_double">
<class name="Customer" table="customers">
<id name="id" column="id" type="int">
<generator class="native"></generator>
</id>
<property name="name" column="name" type="string"></property>
<property name="age" column="age" type="int"></property>
<!-- set标签用于映射单向一对多
name表示单方的关联属性
table表示多方对应表的名字
key-cloumn表示多方对应表的外键
one-to-many-class表示单方关联属性中的每个元素的类型
-->
<set name="orderSet" table="orders" cascade="all" inverse="true">
<key column="customers_id"></key>
<one-to-many class="Order"/>
</set>
</class>
<!-- 映射类的多方 -->
<class name="Order" table="Orders">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<property name="orderNo" column="orderNo"></property>
<property name="price" column="price"></property>
<many-to-one name="customer" column="customers_id"></many-to-one>
</class>
</hibernate-mapping>
测试代码如下:
/**
* 优化:保存1个客户,级联增加2个订单,设置双向关联,共3条SQL
在Customer单方配置了一个inverse=true属性,即让Order多方来维护SQL
*/
@Test
public void Test02(){
Customer customer=new Customer("牛人2号",23);
Order o1=new Order("编号40003",350);
Order o2=new Order("编号40004",450);
//设置双向关联
customer.getOrderSet().add(o1);
customer.getOrderSet().add(o2);
o1.setCustomer(customer);
o2.setCustomer(customer);
Session session=HibernateUtils.getSession();
Transaction t=session.getTransaction();
try{
t.begin();
session.save(customer);
t.commit();
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
t.rollback();
}finally{
HibernateUtils.closeSession();
}
}
执行结果如下:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into customers (name, age) values (?, ?)
Hibernate: insert into Orders (orderNo, price, customers_id) values (?, ?, ?)
Hibernate: insert into Orders (orderNo, price, customers_id) values (?, ?, ?)
所以说我们在用Hibernate做项目中,最好在多的一方声明为主控方,有一方来维护两者之间的关系,这样既能达到优化程序的目的,又能防止两者一起维护时带来意想不到的错误。