(一)hibernate 优化笔记:基础
二.hibernate的映射:一对多关联关系
hibernate的映射可以说是hibernate中最复杂的部分了。我们一步一步来,首先说一对多关联关系,我们知道在数据库只能用外键而且只能出表示一对多和多对一的单向关系,而在hibernate中还有另外一种就是一对多双向关联。
Order到Customer的多对一单项关联
Customer到Order的一对多单项关联
Customer和Order的一对多双向关联
1.多对一的单向关联关系
第一次我把整个映射文件列出来,后面我就只列关键部分了
Order.hbm.xml文件配置如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping >
<class name="mypack.Order" table="ORDERS">
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="orderNumber" type="string" >
<column name="ORDER_NUMBER" length="15" />
</property>
<many-to-one
name="customer"
column="CUSTOMER_ID"
class="mypack.Customer"
not-null="true"
lazy="false"
/>
</class>
</hibernate-mapping>
BusinessService.java的代码如下:
package mypack;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import java.util.*;
public class BusinessService{
public static SessionFactory sessionFactory;
static{
try{
/* 初始化hibernate,建立SessionFactory实例*/
Configuration config = new Configuration();
config.configure();
sessionFactory = config.buildSessionFactory();
}catch(RuntimeException e){e.printStackTrace();throw e;}
}
/* 查询customer对象关联的所有order对象*/
public List findOrdersByCustomer(Customer customer){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
List orders=session.createQuery("from Order as o where o.customer.id="+customer.getId())
.list();
tx.commit();
return orders;
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
}
/* 按照OID查询customer对象*/
public Customer findCustomer(long customer_id){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer=(Customer)session.get(Customer.class,new Long(customer_id));
tx.commit();
return customer;
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
}
/*级联保存customer和order对象,该方法的前提是在Order.hbm.xml中的<many-to-one> 标签中配置casecade="save-update",
* 当保存Order时,会自动持久化处于临时状态的customer对象,保存到数据库时会级联保存那个“one”,也即是customer对象*/
public void saveCustomerAndOrderWithCascade(){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer=new Customer("Jack");
Order order1=new Order("Jack_Order001",customer);
Order order2=new Order("Jack_Order002",customer);
session.save(order1);
session.save(order2);
tx.commit();
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
/* 分别保存Customer和Order对象(主动持久化Customer),
* 也可以达到saveCustomerAndOrderWithCascade的效果,而且不用配置casecade="save-update",
*关于这个在实际应用中哪一个比较好还要看实际要求,就客户和订单这方面来说,肯定要配置casecade比较好,因为不可能存在没有客户的订单吧!*/
public void saveCustomerAndOrder(){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer=new Customer("Tom");
session.save(customer);
Order order1=new Order("Tom_Order001",customer);
Order order2=new Order("Tom_Order002",customer);
session.save(order1);
session.save(order2);
tx.commit();
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
} finally {
session.close();
}
}
/*打印订单*/
public void printOrders(List orders){
for (Iterator it = orders.iterator(); it.hasNext();) {
Order order=(Order)it.next();
System.out.println("OrderNumber of "+order.getCustomer().getName()+ " :"+order.getOrderNumber());
}
}
public void test(){
// saveCustomerAndOrder();
saveCustomerAndOrderWithCascade();
System.out.println("\n\n****************打印客户号为1的所有Order********************");
Customer customer=findCustomer(1);
List orders=findOrdersByCustomer(customer);
printOrders(orders);
}
public static void main(String args[]){
new BusinessService().test();
sessionFactory.close();
}
}
customer的配置我就不写了,注意上面的配置order.hbm,xml中的not-null=”true”表明该字段是不允许为空的,也就是插入一个order的时候必须指定其customer的ID。
【运行结果】 :
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, ID) values (?, ?)
Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID, ID) values (?, ?, ?)
Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID, ID) values (?, ?, ?)
****************打印客户号为1的所有Order********************
Hibernate: select customer0_.ID as ID0_, customer0_.NAME as NAME0_0_ from CUSTOMERS custom
er0_ where customer0_.ID=?
Hibernate: select order0_.ID as ID, order0_.ORDER_NUMBER as ORDER2_1_, order0_.CUSTOMER_ID
as CUSTOMER3_1_ from ORDERS order0_ where order0_.CUSTOMER_ID=1
Hibernate: select customer0_.ID as ID0_, customer0_.NAME as NAME0_0_ from CUSTOMERS custom
er0_ where customer0_.ID=?
OrderNumber of Tom :Tom_Order001
OrderNumber of Tom :Tom_Order002
2.一对多的双向关联关系
上面的Order.hbm,xml配置不变,所以我们拥有从order到Customer的单向关联,如果要查询某个订单的Customer,我们直接使用order.getCustomers()就可以了,那我们怎么才能拥有从Customer到order的关联呢?当这里两个关联都有了,那么就一对多的双向关联,我们要实现的需求就是直接customer.getOrders()就取出这个客户的所有订单了。当然这其中还有很多实际应用方面的另外要求,比如作为一个商场不可能客户以来就把他所有的订单都取出来吧,这其中我们要怎么控制,怎么配置我们也会说到。
在Customer.java中要增加如下声明并提供其set和get方法:
private Set orders = new HashSet();
根据上面给出Customer.hbm.xml的配置:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="mypack.Customer" table="CUSTOMERS">
<id name="id" type="long" column="ID">
<generator class="increment" />
</id>
<property name="name" type="string">
<column name="NAME" length="15" />
</property>
<set name="orders" cascade="save-update">
<key column="CUSTOMER_ID" />
<one-to-many class="mypack.Order" />
</set>
</class>
</hibernate-mapping>
2.1配置介绍:上面配置了cascade="save-update" 表明当保存或更新Customer对象时,会级联保存或更新orders集合中的所有order对象,如下面的方法:
public void saveCustomerAndOrderWithCascade(){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
//创建customer和order对象
Customer customer=new Customer("Tom",new HashSet());
Order order=new Order();
order.setOrderNumber("Tom_Order001");
//建立customer和order的关联关系
order.setCustomer(customer);
customer.getOrders().add(order);//将order加入到customer的set中
// 保存Customer对象,hibernate会级联保存orders
session.save(customer);
tx.commit();
idOfTom=customer.getId();
idOfTomOrder=order.getId();
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
该方法的【运行结果】是:
Hibernate: insert into CUSTOMERS (NAME, ID) values (?, ?)
Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID, ID) values (?, ?, ?)
2.2介绍<set>元素的inverse属性
我们首先假设数据库中有两个没有关联的Custermer和Order,我们要将其取出,并建立关联关系。其方法如下:
public void associateCustomerAndOrder(){
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,idOfJack);
Order order=(Order)session.load(Order.class,idOfJackOrder);
order.setCustomer(customer); //建立custermer到order的关联
customer.getOrders().add(order);//将order加入到custermer的set中
tx.commit(); //根据持久化对象的状态执行相应sql语句
}catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
e.printStackTrace();
} finally {
session.close();
}
}
上面方法运行后的【结果】是:
update ORDERS set ORDER_NUMBER = ‘JACK_Oredr001’,CUSTOMER_ID=2 where ID=2
update ORDERS set CUSTOMER_ID=2 where ID=2
我们在数据库中明明只修改了一条记录,为什么会有两个sql语句呢,原来是因为hibernate会安装持久化对象的属性变化来同步更新数据库,
当执行到
order.setCustomer(customer);
时,hibernate检测到order的变化则会计划执行相应如下的sql语句:
update ORDERS set ORDER_NUMBER = ‘JACK_Oredr001’,CUSTOMER_ID=2 where ID=2
当执行到
customer.getOrders().add(order);//将order加入到custermer的set中
时,hibernate有检测到customer有上述变化了,于是执行如下sql语句:
update ORDERS set CUSTOMER_ID=2 where ID=2
显然,这一步是完全没有必要的,为提高hibernate性能,防止执行多余的sql语句,我们可以在Customer.hbm.xml中的<set>元素中加入如下配置inverse="true",这段代码表明Customer关联的知识Order端的镜像,当hibernate探测到持久化对象Customer和Order都发生变化时,只安装Order的变化来同步更新数据库。
其实:我们上面的代码中如果注释掉这段代码,
order.setCustomer(customer);//建立custermer到order的关联
我们即使不是设置inverse属性,程序也只执行
update ORDERS set ORDER_NUMBER = ‘JACK_Oredr001’,CUSTOMER_ID=2 where ID=2
这一段sql语句,
Tip:但是我们为了程序的健壮性,在两个对象有双向关联关系的时候,我们应该同时修改两端的对象的响应属性,为避免执行多余的sql语句,我们还应该在set中设置inverse属性,亦然我们在解除双向关联的关系时,也应该修改两端的属性,执行如下代码
customer.getOrders().remove(order);
order.setCustomer(null);
2.3级联删除
考虑我们在删除某个Customer的时候,肯定也要删除对应order的记录,我们就应该设置cascade="delete"
考虑我们在解除某个Customer和某Order的关联关系的时候,如果要删除该order的记录,同时我们还要保证其“save-update“,和”delete”的功能,我们就可以设置cascade="all-delete-orphan"(orphan是“孤儿”的意思)
关于casecade的配置详细表如下:
<!--[endif]-->
2.一对多的双向自身关联关系
<!--[endif]-->
自身关联
该类Category.hbm.xml的配置如下:
<hibernate-mapping >
<class name="mypack.Category" table="CATEGORIES" >
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" >
<column name="NAME" length="15" />
</property>
<set
name="childCategories"
cascade="save-update"
inverse="true"
>
<key column="CATEGORY_ID" />
<one-to-many class="mypack.Category" />
</set>
<many-to-one
name="parentCategory"
column="CATEGORY_ID"
class="mypack.Category"
/>
</class>
</hibernate-mapping>
hibernate的映射到此先告以段落,但是你如果以为hibernate的映射到此就结束了就大错特错了,hibernate的映射远不止这一点。但是上面的是平时比较常用的方式。关于映射我们后面会继续深入来讨论。下一节先打个基础说说hibernate是如何操纵对象的。
相关推荐
### Hibernate映射笔记详解 #### Hibernate映射文件与配置关系 Hibernate映射是ORM(对象关系映射)框架中的一项关键技术,它允许开发者在数据库表和Java对象之间建立映射关系,从而简化了数据访问层的开发工作。...
以上便是对Hibernate基础的概览,实际开发中,还需要深入了解实体关系映射、集合映射、级联操作、缓存机制、事务管理、性能优化等方面的知识,才能更好地利用Hibernate提升开发效率并保证应用程序的稳定运行。...
Hibernate学习笔记整理 以下是 Hibernate 框架的详细知识点: Hibernate 介绍 Hibernate 是一个 ORM(Object-Relational Mapping)框架,用于将 Java 对象映射到数据库表中。它提供了一个简洁的方式来访问和操作...
第9课 Hibernate的重点学习:Hibernate的对象关系映射 12 一、对象---关系映射模式 12 二、常用的O/R映射框架: 13 第10课 模拟Hibernate原理(OR模拟) 13 一、 项目名称 13 二、 原代码 13 第11课 Hibernate基础配置...
Hibernate 是一个开源的对象关系映射(ORM)框架,它允许Java开发者使用面向对象的方式来操作数据库。这个框架将数据库操作转化为对Java对象的操作,简化了数据持久化的复杂度。以下是对Hibernate的一些关键知识点的...
7. **性能优化**:Hibernate的性能优化主要包括缓存机制(第一级缓存、第二级缓存)、批处理、延迟加载等策略,通过合理设置和使用,可以显著提高应用程序的运行效率。 8. **Annotation与XML配置**:Hibernate支持...
首先,我们来看集合类型在Hibernate中的映射: 1. **单值Collection**: 这种情况通常指的是一个对象与多个其他对象的一对多关系。例如,一个人可以有多个电子邮件地址。在Hibernate中,这可以通过`<set>`标签来实现...
《韩顺平.2011版.hibernate笔记》是一份针对Hibernate框架的详细学习资料,由知名IT讲师韩顺平在2011年编撰而成。Hibernate是Java开发领域中广泛使用的对象关系映射(ORM)框架,它极大地简化了数据库操作,使开发者...
- 对象关系映射:将Java对象与数据库表建立一对一、一对多、多对一、多对多的映射关系。 - 缓存机制:提供第一级缓存(Session级别的)和第二级缓存(SessionFactory级别的),提高性能。 - 支持懒加载和立即加载:...
### 马士兵Java框架Hibernate学习笔记 #### 一、HelloWorld - **知识点概述**: - **项目搭建**:介绍了如何从零开始搭建一个简单的Hibernate项目。 - **环境配置**:包括了如何配置MySQL数据库、创建必要的表...
**Hibernate学习笔记与总结** Hibernate 是一款开源的对象关系映射(ORM)框架,它为Java开发者提供了一种在关系数据库上操作对象数据的便捷方式。本文将深入探讨Hibernate的核心概念、配置、实体类、映射文件、...
**描述解析:**虽然描述为空,但根据标题可以推测这篇博客可能详细讲解了如何使用Hibernate的主要API进行数据操作,并且涉及到了Hibernate配置文件中的常量设置,这些设置对于优化性能和确保正确性至关重要。...
在深入探讨Hibernate学习笔记第二天的源码之前,我们先来理解一下Hibernate的核心概念。Hibernate是一个开源的对象关系映射(ORM)框架,它允许Java开发者将数据库操作转化为对象模型,大大简化了数据访问层的开发...
【hibernate笔记】 课程内容: 本笔记涵盖了Hibernate框架的基础知识和使用技巧,从HelloWorld开始,逐步深入到ORM(对象关系映射)原理、配置、核心接口、对象状态、关系映射、查询语言HQL,以及在实际项目中的...
在本篇中,我们将深入探讨Hibernate中的单一映射机制,这是一种在Java应用程序中实现对象关系映射(ORM)的关键技术。Hibernate是一个流行的开源框架,它简化了与数据库的交互,通过对象模型自动处理数据的持久化。...
第三课:hibernate基本映射 第四课:hibernate多对一关联映射 ...................... Spring: 第一课:构建Spring的环境并建立一个例子 第三课:spring Bean的作用域 第四课:spring对AOP的只是(采用Annotation的...
06 06Hibernate_Collection : Hibernate的容器映射技术,包括list、set和map等。用法大体一致,数据库中的两张表,在实体层设计和配置文件都只有一个 其中数据库用到级联删除。配置文件分别用list、set和map元素...
《Hibernate入门:第一天笔记详解》 Hibernate,作为Java领域中著名的ORM(Object-Relational Mapping)框架,极大地简化了数据库操作,让开发者可以更加专注于业务逻辑而不是底层的数据访问。本文将基于第一天学习...