(一)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_容器映射技术笔记Hibernate_容器映射技术笔记Hibernate_容器映射技术笔记
第9课 Hibernate的重点学习:Hibernate的对象关系映射 12 一、对象---关系映射模式 12 二、常用的O/R映射框架: 13 第10课 模拟Hibernate原理(OR模拟) 13 一、 项目名称 13 二、 原代码 13 第11课 Hibernate基础配置...
Hibernate开发过程(单一映射体) 1创建持久类XXXX.java(要有oid字段:唯一且不具有业务含义;所有属性都有getter/setter方法;空的构造方法;不含oid的构造方法) 2创建映射文件XXXX.hbm.xml(包,类,id,字段) 3...
第三课:hibernate基本映射 第四课:hibernate多对一关联映射 ...................... Spring: 第一课:构建Spring的环境并建立一个例子 第三课:spring Bean的作用域 第四课:spring对AOP的只是(采用Annotation的...
06 06Hibernate_Collection : Hibernate的容器映射技术,包括list、set和map等。用法大体一致,数据库中的两张表,在实体层设计和配置文件都只有一个 其中数据库用到级联删除。配置文件分别用list、set和map元素...
hibernate概述,hibernate入门Demo,hibernate配置文件详解(全局配置,实体类映射配置),配置实体规则,核心API详解(Configuration,sessionFactory,session,Transaction),hibernate中的对象状态以及刷新能缓存机制 ...
Hibernate 学习笔记 Hibernate 学习笔记 1 第一个hibernate项目(hibernate_first) 2 测试实体对象的生命周期(hibernate_session) 3 hibernate基本映射(hibernate_basemapping) 4 class实体类---表 4 标签id 5 ...
关于hibernate的Session,向数据插入时的事务隔离级别,持久化对象的状态,对应关系的映射文件,表与表之间的多种映射关系,以及hibernate的二级缓存的笔记。
001 Hibernate 简介(开源 O/R 映射框架) 002 第一个 Hibernate 示例 003 hibernate 主要接口介绍 004 持久对象的生命周期介绍 005 query 接口初步 ...028 hibernate 缓存(性能优化策略) 029 hibernate 抓取策略
Hibernate3 学习笔记.ppt 一、O/R Mapping 二、Hibernate入门 三、Hibernate映射申明(Mapping declaration) 四、Hibernate Annotations 五、持久化对象的状态和生命周期 六、Hibernate查询 七、Hibernate最佳实践 ...
Hibernate知识文档: 一、第一个hibernate项目 1、新建一个java项目 2、创建User Library,加入jar包 * HIBERNATE_HOME/lib/*.jar * HIBERNATE_HOME/lib/hibernate3.jar * MySql JDBC驱动 3、提供hibernate....
里面包含Hibernate实体映射的具体实例代码,还有相关教程笔记,喜欢的可以学习学习。
Hibernate学习笔记(java的) 包括基础的使用和配置,有Hibernate的控制事务,映射关系等内容。 可快速入门,也可当手册使用。 更多:http://download.csdn.net/user/daillo/all
Hibernate环境搭建 Hibernate主要接口 Hibernate主要映射 Hibernate的lazy、fetch、cascade等策略 Hibernate性能优化
J2EE三大框架_笔记 共分三块: J2EE框架_笔记_a: 1-JSP+JDBC_假分页笔记 2-JSP+JDBC_真分页(基于Oracle数据库分页)笔记 3-JSP+DAO和MVC+DAO(基于MySQL数据库分页...54留言管理程序_Struts + Spring + Hibernate笔记
J2EE三大框架_笔记 共分三块: J2EE框架_笔记_a: 1-JSP+JDBC_假分页笔记 2-JSP+JDBC_真分页(基于Oracle数据库分页)笔记 3-JSP+DAO和MVC+DAO(基于MySQL数据库分页...54留言管理程序_Struts + Spring + Hibernate笔记
J2EE三大框架_笔记 共分三块: J2EE框架_笔记_a: 1-JSP+JDBC_假分页笔记 2-JSP+JDBC_真分页(基于Oracle数据库分页)笔记 3-JSP+DAO和MVC+DAO(基于MySQL数据库分页...54留言管理程序_Struts + Spring + Hibernate笔记
hibernate的word笔记,其中包括了初始的hibernate的关系映射,以及各种关于hibernate的相关知识,配置之类的
Hibernate_映射配置文件详解,很好用的学习文件