关于hibernate中持久化类之间的映射关系的详解(一)
2017-02-17 21:20
375 查看
从传统程序的开发角度来讲,在一个项目的启动阶段我们通常要根据项目的需求来建立数据库中的表,并根据实际应用中的关系来建立表与表之间的关系。而hibernate的出现却完全颠覆的这种思想,它是一种面想对象的持久层框架。在这里你可以通过对象之间的映射关系让框架在底层实现数据库的建立。个人感觉虽然这样做很符合java面向对象的编程思想,但是其对数据库操作的深度封装,在大型或者更为复杂业务逻辑的项目中似乎显得有些笨拙。这里作为一个新手我也是刚刚接触hibernate的一些框架体系,并在学习的过程中产生了一些感悟,希望这些感悟在以后的编程学习与开发中能够见证自己的一步步的成长。
言归正传,在hibernate中我们如何通建立过持久化类中的映射关系来轻松解决数据库中的复杂的建表关系呢?那么下面我们就通过代码来深入的了解一下
一对多的映射关系(重要)
1.1 这是我们的客户实体类
通过级设置,我们就可以轻松实现客户与订单信息的保存,那么当我们的订单与客户之间存在级联的导航关系时我们在存储时会有什么不一样的地方的,首先我们来看一张导航图:
好了,以上就是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<Order> orders = new HashSet<Order>(); //可以对应多个的订单 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<Order> getOrders() { return orders; } public void setOrders(Set<Order> 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的映射文件信息
<?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属性:类的全路径名称 table属性:表名称 --> <class name="com.hibernate.demo2.Order" table="orders" > <!-- 建立类中属性与表中字段映射 --> <!-- 唯一标示 --> <!-- 使用id标签配置唯一属性 ,在标签中还需配置一个主键生成策略--> <id name="oid" column="oid"> <generator class="native" /> </id> <!-- 普通属性 --> <!-- property标签:用于映射普通属性 name:属性名称 column:表中字段名称 --> <property name="addr" column="addr" length="50" /> <!-- =====================这里就是相对于订单配置映射的关系(Start)====================== --> <!-- 多对一的关系<many-to-one>标签: name:关联对象的属性的名称 colum:表中的外键名称(对应Customer中的主键uid) class:关联对象类的全路径 --> <many-to-one name="customer" column="uno" class="com.hibernate.demo2.Customer" /> <!-- =====================这里就是配置映射的关系(Start)====================== --> </class> </hibernate-mapping>
同时我们还要设置Customer的映射文件来映射对应Order的关系,这里是Customer的映射文件信息
<?xml version="1.0" encoding="UTF-8"?> &l c36f t;!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属性:类的全路径名称 table属性:表名称 --> <class name="com.hibernate.demo2.Customer" table="customer"> <!-- 建立类中属性与表中字段映射 --> <!-- 唯一标示 --> <!-- 使用id标签配置唯一属性 ,在标签中还需配置一个主键生成策略--> <id name="cid" column="cid"> <generator class="native" /> </id> <!-- 普通属性 --> <!-- property标签:用于映射普通属性 name:属性名称 column:表中字段名称 --> <property name="cname" column="cname" length="30" /> <!-- 建立映射 --> <!-- 配置一个几个<set>的name Customer对象中的关联对象的属性名称 --> <set name="orders"> <!-- <key>标签中的colum:用来描述一对多,多的一方的外键名称 --> <key column="cno"></key> <!-- 配置<one-to-many>标签中class属性:订单类的全路径 --> <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(); }
通过上面的代码,我们在想既然我们订单与客户之间已经存在了关系,为什么保存完客户之后还要保存订单呢?能不能只在保存客户的同时我们的订单信息也就随之对应下来了呢?答案是可以的,这就需要我们去映射文件中去配置一下级联属性了。 这里只需要在我们刚才配置的<set>集合标签中添加一个cascade="save-update"的属性,在测试代码中只要我们把订单添加到用户的订单集合中,保存客户时订单也会与之对应保存
<set name="orders" cascade="save-update">
下面来看一下测试代码: 注意:如果我们没有添加上面的一行属性的话,当我们执行下面的代码时就会报出一个异常,意思是:持久态类与瞬时态类建立了关系,在hibernate中没有设置级联关系这样做是不可以的
@Test //保存客户和订单的时候,是否可以只保存其中的一方,需要保存客户级联订单才可以 //<set>集合是客户的关联订单对象的集合,所以在<set>标签上去配置一个属性: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中<many-to-one>配置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中一对多的映射关系,如果一对多的映射关系能够熟练掌握那么一对一,多对多也就能迎刃而解,希望这里的讲解能够对你有帮助!
相关文章推荐
- 关于hibernate中持久化类之间的映射关系的详解(一)
- JAVAWEB开发之Hibernate详解(四)——持久化类的继承映射关系
- JAVAWEB开发之Hibernate详解(四)——持久化类的继承映射关系
- Hibernate笔记2--映射对象之间的关系
- Hibernate映射对象之间的多种关系
- Java类型、Hibernate映射类型和SQL类型之间的对应关系
- [原创]java WEB学习笔记77:Hibernate学习之路---Hibernate 版本 helloword 与 解析,.环境搭建,hibernate.cfg.xml文件及参数说明,持久化类,对象-关系映射文件.hbm.xml,Hibernate API (Configuration 类,SessionFactory 接口,Session 接口,Transaction(事务))
- Hibernate基于注解方式配置来实现实体和数据库之间存在某种映射关系
- Hibernate 一张表细化操作及表之间继承关系的映射配置
- Hibernate映射的基本操作 Java类型、Hibernate映射类型以及SQL类型之间的对应关系
- Hibernate中 多对一,一对多映射关系分析详解
- java类型、hibernate映射类型和sql类型之间的对应关系
- hibernate中List一对多映射关系详解
- 关于camera calibration以后三维空间和二维图像之间的映射关系的讨论
- Hibernate中映射关系 一对一 详解
- hibernate映射详解之: 对象 - 关系映射
- java类型,hibernate映射类型以及SQL类型之间的对应关系
- hibernate中List一对多映射关系详解
- Hibernate学习之 -- 使用Middlegen-Hibernate-r5创建oracle10g的table的hibernate映射文件,Hibernate学习笔记三 ---持久化类和关系数据
- SSH——Hibernate继承关系映射详解(配置+实例+总结)