从传统程序的开发角度来讲,在一个项目的启动阶段我们通常要根据项目的需求来建立数据库中的表,并根据实际应用中的关系来建立表与表之间的关系。而hibernate的出现却完全颠覆的这种思想,它是一种面想对象的持久层框架。在这里你可以通过对象之间的映射关系让框架在底层实现数据库的建立。个人感觉虽然这样做很符合java面向对象的编程思想,但是其对数据库操作的深度封装,在大型或者更为复杂业务逻辑的项目中似乎显得有些笨拙。这里作为一个新手我也是刚刚接触hibernate的一些框架体系,并在学习的过程中产生了一些感悟,希望这些感悟在以后的编程学习与开发中能够见证自己的一步步的成长。
言归正传,在hibernate中我们如何通建立过持久化类中的映射关系来轻松解决数据库中的复杂的建表关系呢?那么下面我们就通过代码来深入的了解一下
一对多的映射关系(重要)
1.1 这是我们的客户实体类
package com.hibernate.demo2;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Integer cid; //客户id,唯一主键
private String cname; //客户姓名
private Set orders = new HashSet(); //可以对应多个的订单
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set getOrders() {
return orders;
}
public void setOrders(Set orders) {
this.orders = orders;
}
}
1.2这是订单的实体类
package com.hibernate.demo2;
public class Order {
private Integer oid; //订单的id,唯一主键
private String addr; //订单中物品的邮寄地址
private Customer customer;//订单属于某一个客户,要放置一个客户的对象
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
1.3在实际应用场景中,一个客户是可以有多个订单,而一个订单只能对应一个客户,也就是说客户相对于订单是一对多的关系,订单相对于客户是多对一的关系,那么下面我们就先通过一个张图来描述一对多是如何建立关系,再根据图在实体的映射文件中来设置这两个实体类之间的映射关系
图中我们要实现用户预订单一对多的关系,我们需要在订单表中添加一个外键并对应用户的主键
这是Order的映射文件信息
<hibernate-mapping>
<class name="com.hibernate.demo2.Order" table="orders" >
<id name="oid" column="oid">
<generator class="native" />
id>
<property name="addr" column="addr" length="50" />
<many-to-one name="customer" column="uno" class="com.hibernate.demo2.Customer" />
class>
hibernate-mapping>
同时我们还要设置Customer的映射文件来映射对应Order的关系,这里是Customer的映射文件信息
<hibernate-mapping>
<class name="com.hibernate.demo2.Customer" table="customer">
<id name="cid" column="cid">
<generator class="native" />
id>
<property name="cname" column="cname" length="30" />
<set name="orders">
<key column="cno">key>
<one-to-many class="com.hibernate.demo2.Order"/>
set>
class>
hibernate-mapping>
到这里我们就解决了两个实体类的之间的映射关系,那么对于客户与订单的添加又怎样来实现呢?下面我们来看一下代码:
第一种做法:先创建用户和订单----->在订单中添加用户----->在用户中生成订单------->保存用户-------->保存订单。
@Test
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
//定义一个客户:
Customer customer = new Customer();
customer.setCname("项羽");
//定义两个订单
//订单2
Order order1 = new Order();
order1.setAddr("北京");
//订单2
Order order2 = new Order();
order2.setAddr("上海");
order1.setCustomer(customer);
order2.setCustomer(customer);
customer.getOrders().add(order1);
customer.getOrders().add(order2);
session.save(customer);
session.save(order1);
session.save(order2);
tx.commit();
session.close();
}
通过上面的代码,我们在想既然我们订单与客户之间已经存在了关系,为什么保存完客户之后还要保存订单呢?能不能只在保存客户的同时我们的订单信息也就随之对应下来了呢?答案是可以的,这就需要我们去映射文件中去配置一下级联属性了。
这里只需要在我们刚才配置的集合标签中添加一个cascade="save-update"的属性,在测试代码中只要我们把订单添加到用户的订单集合中,保存客户时订单也会与之对应保存
<set name="orders" cascade="save-update">
下面来看一下测试代码:
注意:如果我们没有添加上面的一行属性的话,当我们执行下面的代码时就会报出一个异常,意思是:持久态类与瞬时态类建立了关系,在hibernate中没有设置级联关系这样做是不可以的
@Test
//保存客户和订单的时候,是否可以只保存其中的一方,需要保存客户级联订单才可以
//集合是客户的关联订单对象的集合,所以在标签上去配置一个属性:cascade
public void demo2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCname("关羽");
Order order1 = new Order();
order1.setAddr("北京");
Order order2 = new Order();
order2.setAddr("广州");
/*设置级联关系*/
customer.getOrders().add(order1);
customer.getOrders().add(order2);
/**保存客户级联订单**/
session.save(customer);
tx.commit();
session.close();
}
与上面同理,下面我们来实现当保存订单信息时客户信息也随之保存的操作
在配置文件上会有一点小区别
这里只需要在Order.hbm.xml中配置cascade属性,在测试代码中只要我们把用户添加到订单的信息中,保存订单客户时客户也会与之对应保存
<set name="orders" cascade="save-update">
下面来看一下测试代码:
@Test
//保存订单级联订单客户
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCname("刘邦");
Order order1 = new Order();
order1.setAddr("武汉");
Order order2 = new Order();
order2.setAddr("长沙");
/*设置级联关系*/
order1.setCustomer(customer);
order2.setCustomer(customer);
/**保存订单级联订单客户**/
session.save(order1);
session.save(order2);
tx.commit();
session.close();
}
通过级设置,我们就可以轻松实现客户与订单信息的保存,那么当我们的订单与客户之间存在级联的导航关系时我们在存储时会有什么不一样的地方的,首先我们来看一张导航图:
通过图片我们来试图解决这些问题:
1.首先order1关联了customer,而customer没有关联order1,
2.customer关联到order2、order3 而order2 order3 没有关联到customer
问题一答案:也就是说当我们保存order1时通过级联关系customer会保存,当customer保存时,通过级联关系order2与order3都会被保存,因此这里实际上对数据库一共执行了4次insert操作
问题二答案:而当保存customer时因为customer没有关联order1因此order1不会执行保存操作,可知这里实际上对数据库这一共执行了3次insert操作
问题三答案:当保存order2时由于order2没有关联customer因此customer不会保存,所以虽然customer关联了order3但是customer没有被保存order3也就谈不上会被保存,可知这里实际上只执行了一条对order2的insert操作。
好了,以上就是hibernate中一对多的映射关系,如果一对多的映射关系能够熟练掌握那么一对一,多对多也就能迎刃而解,希望这里的讲解能够对你有帮助!