我们以客户(Customer)与订单(Order)为例
实体类创建
Order订单实体类
//订单-----多的一方
public class Order {
private Integer id;
private Double money;
private String receiverInfo; // 收货地址
// 订单与客户关联
private Customer c; // 描述订单属于某一个客户
public Customer getC() {
return c;
}
public void setC(Customer c) {
this.c = 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 getReceiverInfo() {
return receiverInfo;
}
public void setReceiverInfo(String receiverInfo) {
this.receiverInfo = receiverInfo;
}
}
Customer客户实体类
//客户 ------一的一方
public class Customer {
private Integer id; // 主键
private String name; // 姓名
// 描述客户可以有多个订单
private Set<Order> orders = new HashSet<Order>();
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
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;
}
}
Hbm映射文件编写
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="cn.nwtxxb.oneToMany.Order" table="t_order">
<id name="id" column="c_id">
<generator class="identity" />
</id>
<property name="money" column="c_money" />
<property name="receiverInfo" column="c_receiverInfo" length="50"/>
<!-- 多对一 -->
<many-to-one fetch="join" lazy="false" name="c" class="cn.nwtxxb.oneToMany.Customer" column="c_customer_id">
</many-to-one>
<!--
name属性它描述的是Order类中的一的一方的属性名称 Customer c;
class 代表一的一方的类型
column 描述的是一对多,在多的一方产生的外键的名称 c_customer_id
-->
</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="cn.nwtxxb.oneToMany.Customer" table="t_customer">
<id name="id" column="c_id">
<generator class="identity" />
</id>
<property name="name" column="c_name" length="20" />
<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="save-update">
<key column="c_customer_id" />
<one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>
<!-- 使用set来描述在一的一方中关联的多 Set<Order>,它的name属性就是set集合的名称 key:它主要描述关联的多的一方产生的外键名称,注意要与多的一方定义的外键名称相同
one-to-many 描述集合中的类型 -->
</class>
</hibernate-mapping>
测试保存
public class OneToManyTest {
// 测试保存
@Test
public void test1() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
// 2.3建立关系
// 2.3.1 订单关联客户
o1.setC(c);
o2.setC(c);
// 2.3.2 客户关联订单
c.getOrders().add(o1);
c.getOrders().add(o2);
session.save(o1);
session.save(o2);
session.save(c);
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
}
上面操作是一种双向关联
问题:我们可不可以只保存订单或只保存客户完成保存操作?
测试单向关联保存
// 测试保存---单向操作(保存订单并自动保存客户)
@Test
public void test2() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
// 2.3建立关系
// 2.3.1 订单关联客户
o1.setC(c);
o2.setC(c);
session.save(o1); // o1是一个持久化对象
session.save(o2); // o2是一个持久化对象
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: cn.nwtxxb.oneToMany.Customer
…………..
这个异常代表提一个持久化对象关联了一个瞬时对象。
我们可以使用级联操作来解决上述的问题.
我们现在要做的是保存订单时保存客户,需要在订单的hbm配置文件中修改
<!-- 多对一 -->
<many-to-one name="c" class="cn.nwtxxb.oneToMany.Customer" column="c_customer_id" cascade="save-update">
</many-to-one>
设置cascade=save-update 那么在保存订单时就可以自动将客户保存。
如果我们要完成保存客户时,保存订单
<!-- 一个客户关联多个订单 -->
<set name="orders" cascade="save-update">
<key column="c_customer_id" />
<one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>
双向关联保存
我们在开发中要配置双向关联配置。———可以通过任意一方来操作对方
在操作代码,尽量来要进行单向关联。——可以尽量资源浪费。
在双向关联中,会存在多余的update语句。
我们可以使用inverse属性来设置,双向关联时由哪一方来维护表与表之间的关系。
<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="save-update">
<key column="c_customer_id" />
<one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>
Inverse它的值如果为true代表,由对方来维护外键。
Inverse它的值如果为false代表,由本方来维护外键。
关于inverse的取值:
外键在哪一个表中,我们就让哪一方来维护外键。
对象导航
级联删除
我们在删除客户时,也要删除订单,如果没有做级联,那么这个操作是不允许。
为了维护数据完整性
<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="delete">
<key column="c_customer_id" />
<one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>
delete-orphan用法
<!-- 一个客户关联多个订单 -->
<set name="orders" inverse="true" cascade="delete-orphan">
<key column="c_customer_id" />
<one-to-many class="cn.nwtxxb.oneToMany.Order" />
</set>
测试类
public class OneToManyTest {
// 级联 cascade= delete-orphan
@Test
public void test6() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 得到客户
Customer c = session.get(Customer.class, 2);
// 得到客户的订单
Order o = session.get(Order.class, 6);
c.getOrders().remove(o);
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
// 测试级联删除
@Test
public void test5() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 操作----删除订单时,不需要删除客户,当我们删除一个客户时,应该将客户对应订单也删除。
Customer c = session.get(Customer.class, 1);
session.delete(c);// 删除客户?订单是否会删除?
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
// 测试一对多对象导航
@Test
public void test4() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
Order o3 = new Order();
o3.setMoney(3000d);
o3.setReceiverInfo("深圳");
// 描述关系
// o1要关联c
o1.setC(c);
// c要关联o2 o3
c.getOrders().add(o2);
c.getOrders().add(o3);
session.save(o1);
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
// 测试保存---单向操作(保存客户并自动保存订单)
@Test
public void test3() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
// 2.3建立关系
// 2.3.1 客户与订单关联
c.getOrders().add(o1);
c.getOrders().add(o2);
session.save(c);// 保存客户
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
// 测试保存---单向操作(保存订单并自动保存客户)
@Test
public void test2() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
// 2.3建立关系
// 2.3.1 订单关联客户
o1.setC(c);
o2.setC(c);
session.save(o1); // o1是一个持久化对象
session.save(o2); // o2是一个持久化对象
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
// 测试保存
@Test
public void test1() {
// 1.得到session
Session session = HibernateUtils.openSession();
session.beginTransaction();
// 2.操作
// 2.1创建一个客户
Customer c = new Customer();
c.setName("张三");
// 2.2创建两个订单
Order o1 = new Order();
o1.setMoney(1000d);
o1.setReceiverInfo("北京");
Order o2 = new Order();
o2.setMoney(2000d);
o2.setReceiverInfo("上海");
// 2.3建立关系
// 2.3.1 订单关联客户
o1.setC(c);
o2.setC(c);
// 2.3.2 客户关联订单
c.getOrders().add(o1);
c.getOrders().add(o2);
session.save(o1);
session.save(o2);
session.save(c);
// 3.事务提交,关闭
session.getTransaction().commit();
session.close();
}
}
HibernateUtils工具类
public class HibernateUtils {
private static Configuration config;
private static SessionFactory sessionFactory;
static{
config=new Configuration().configure();
sessionFactory=config.buildSessionFactory();
}
public static Session openSession(){
return sessionFactory.openSession();
}
}
cascade级联操作总结
使用cascade可以完成级联操作
它可常用取值:
none这是一个默认值
save-update,当我们配置它时,底层使用save update或save-update完成操作,级联保存临时对象,如果是游离对象,会执行update.
delete 级联删除
delete-ophan 删除与当前对象解除关系的对象。
all 它包含了save-update delete操作
all-delete-orphan 它包信了delete-orphan与all操作
问题:cascade与inverse有什么区别?
cascade它是完成级联操作
Inverse它只有在双向关联情况下有作用,它来指定由哪一方维护外键。