双向关联
以客户和订单为例,创建实体类,
package domain;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Integer id;
private String name;
Set<Order> orders = new HashSet<>();
@Override
public String toString() {
return "Customer [id=" + id + ", name=" + name + "]";
}
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 Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
package domain;
public class Order {
private Integer id;
private Double money;
private String receiveInfo;
private Customer c;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public String getReceiveInfo() {
return receiveInfo;
}
public void setReceiveInfo(String receiveInfo) {
this.receiveInfo = receiveInfo;
}
public Customer getC() {
return c;
}
public void setC(Customer c) {
this.c = c;
}
@Override
public String toString() {
return "Order [id=" + id + ", money=" + money + ", receiveInfo=" + receiveInfo + "]";
}
}
hbm映射文件编写
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="domain.Customer" table="t_customer">
<id name="id" column="id" type="integer">
<generator class="identity"></generator>
</id>
<property name="name" column="name" length="20"></property>
<set name="orders">
<key column="customer_id"></key>
<one-to-many class="domain.Order"/>
</set>
</class>
</hibernate-mapping>
Order.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="domain.Order" table="t_order">
<id name="id" column="id" type="integer">
<generator class="identity"></generator>
</id>
<property name="money" column="money" length="20"></property>
<property name="receiveInfo" column="name" length="20"></property>
<many-to-one name="c" class="domain.Customer" column="customer_id"></many-to-one>
</class>
</hibernate-mapping>
Test
@Test
public void test1(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
Customer c=new Customer();
c.setName("小明");
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiveInfo("北京");
Order o2 =new Order();
o2.setMoney(2000d);
o2.setReceiveInfo("上海");
//建立关系
o1.setC(c);
o2.setC(c);
c.getOrders().add(o1);
c.getOrders().add(o2);
session.save(o1);
session.save(o2);
session.save(c);
session.getTransaction().commit();
session.close();
}
结果是执行了4条update语句
单向关联保存
为了让我们在保存订单的同时自动保存客户,我们需要用到单向关联保存。我们把上面Test中“建立关系”的代码改为
o1.setC(c);
o2.setC(c);
session.save(o1);
session.save(o2);
,然后在Order.hbm.xml中的<many-to-one>
标签添加cascade=”save-update”,这时就能做到单向关联保存了。
双向关联维护
为了使操作更加方便,我们在Customer.hbm.xml的set标签中也添加cascade=”save-update”,再次执行Test,会发现执行了四条update语句,降低了程序效率。这时,可以使用inverse属性来设置由哪一方来维护表与表之间的关系。
在Customer.hbm.xml的set标签中添加inverse="true"
,当设置为true时,表示自己不负责维护外键,当为false时,表示负责维护外键。
级联删除
当想要在删除一个客户的同时,也把其对应的订单删除,这时需要进行级联删除。修改Customer.hbm.xml 中的cascade属性,all包含delete 和 save-update ,all-delete-orphan包含all和delete-orphan。
@Test
public void test4(){
Session session = HibernateUtils.openSession();
session.beginTransaction();
session.delete(session.get(Customer.class, 1));
session.getTransaction().commit();
session.close();
}
结果是同时删掉了customer和对应order。
delete-orphan用于删除孤儿节点。什么是孤儿节点?
比如,将orders中的o1用remove()方法移除,那么o1就成为了孤儿节点,这时如果执行update()或者session.flush()时,Hibernate同步数据库和缓存,会把数据库中的o1对应的记录删掉。
总结
inverse属性:
只有集合标记(set/map/list/array/bag)才能设置inverse属性,它决定是否将对set的改动反映到数据库中去。
inverse和cascade的比较:
inverse只在双向关联中有效,(set+one-to-many/many-to-many),cascade对集合中的每个元素执行关联操作。