Hibernate 级联之OneToMany

首先看看表结构!

customer表:

create table customers

(

    ID bigint not null    primary key auto_increment,

    userName varchar(20)

);

Order表:

create table orders

(

    ID bigint not null primary key auto_increment,

    customers_ID bigint,    --应该为customers(ID)外键

    orderDescription varchar(50)--订单描述

);

有了上面简单的客户表与订单表,来建立一个Project!~并且添加Hibernate~并由上面二张表生成Beans,主键都是native类型~自动递增!

我们将 自动生成的Customer.java    Bean添加一个SET属性,代码如下:

Customers.java

为Order.java   Bean 去掉cid(CustomerID)并添加一个Customer属性,代码如下:

Orders.java

修改Customer.hbm.xml映射文件:

<?xml version="1.0" encoding="GBK"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="fengyan.Hibernate.Customers" table="customers" catalog="study">

        <id name="id" type="java.lang.Long">

            <column name="ID" />

            <generator class="native" />

        </id>

        <property name="userName" type="java.lang.String">

            <column name="userName" length="20" />

        </property>

        <!-- name集合属性orders

             table对应的表名

             cascade 级联关系,当保存或更新时会级联保存与这个Customers对象相关联的所有Orders对象

             inverse=true是将 控权抛出(给Orders) -->

        <set name="orders" table="orders" cascade="save-update" inverse="true">

            <key column="customers_ID"></key><!-- 表字段 -->

            <one-to-many class="fengyan.Hibernate.Orders"/><!-- 关联的类 -->

        </set>

    </class>

</hibernate-mapping>

修改Order.hbm.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="fengyan.Hibernate.Orders" table="orders" catalog="study">

        <id name="id" type="java.lang.Long">

            <column name="ID" />

            <generator class="native" />

        </id>

        <property name="orderDescription" type="java.lang.String">

            <column name="orderDescription" length="50" />

        </property>

        <!-- name属性名

             class对应的类

             column对应的表字段 -->

        <many-to-one name="customer" class="fengyan.Hibernate.Customers" column="customers_ID"></many-to-one>

    </class>

</hibernate-mapping>

然后我们建立一个CustomersDAO操作类

package fengyan.Hibernate;

import org.hibernate.Session;

import org.hibernate.Transaction;

public class CustomersDAO {

    public void save(Customers customer)

    {

        Session session = HibernateSessionFactory.getSession();//会话

        try

        {

            Transaction tx = session.beginTransaction();//事物

            session.save(customer);//保存

            tx.commit();//提交事物

        }

        catch(Exception e)

        {

            System.out.println("DAO has Errors:"+e);

        }

        finally

        {

            session.close();//关闭会话

        }

    }

}

再来建立一个Servlet     MyServlet.java代码如下:

package fengyan.Hibernate;

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {

        //声明一个用户

        Customers customer = new Customers("fengyan");

        //声明二订单

        Orders order1 = new Orders("描述1");

        Orders order2 = new Orders("描述2");

        //订单关联用户

        order1.setCustomer(customer);

        order2.setCustomer(customer);

        //用户关联订单

        customer.getOrders().add(order1);

        customer.getOrders().add(order2);

        //save

        CustomersDAO cd = new CustomersDAO();

        cd.save(customer);//我们仅仅保存了Customers!

    }

}

最后一个JSP测试页面:

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>

<html>

  <head>

    <title>My JSP ‘index.jsp‘ starting page</title>

  </head>

  <body>

   <br>

   <a href="servlet/MyServlet">add</a>

  </body>

</html>

运行效果如下:

我们可以看到,在doGet()方法中,我产仅仅save(customer),并没有save(order)但却执行了三条SQL,由显示的SQL语句我们可以知道,将用户fengyan添加到Customers表中的同时也将 order1及order2添加到Orders表中!

为什么Hibernate会自动帮我们将订单也添加到表中呢,就是我们在Customers.hbm.xml映射配置中,set节点的cascade=save-update,就是当我们保存或更新Customers的时候也会自动保存相应的Orders对象!

当我们现在将 doGet()方法内  订单关联用户的代码注释掉,看一下效果:

从显示的SQL语句看,我们似乎看不出什么区别,但这时如果打开MYSQL,会发现:

我们发现现在Hiberante帮自动插入的Customers_ID字段为空,为什么会这样的呢,我们不是在下面用

//用户关联订单

  customer.getOrders().add(order1);

  customer.getOrders().add(order2);

不是已经由用户关联了订单吗?这是因为我们在Customers.hbm.xml的set节点中加了属性inverse=true,这句话的意思是将主控制权交出去,具体是什么意思呢?就是在一对多关系中将 主动权交出,具体也就是交给了Orders,也就是用户与订单之间从属关系主要是由Orders对象来确定,也即订单自己来决定它属于哪个对象,所以在这里,我们将    订单关联用户的代码注释掉后,虽然后面 用户关联了订单,但因为用户已经将主动权交出,所以Hibernate在帮我们save订单的时候并不知道订单是属于哪个用户,也自然就在Customers_ID字段填空值了!

那么如果此时我们将Customers.hbm.xml中的 inverse=true去掉是不是就行了呢?带着这样的猜想,我来尝试一下,结果如下图:

我们首先查寻数据库发现Hibernate已经正确的将Orders对象持久化到表中了,

同时我们看控制台监视的SQL语句,这时我们发现有五条语句,前三条分别是添加一个用户和二条订单,四五条是修改订单的,具体修改什么,我们发现是修改了customers_ID字段,原来这种情况,Hibernate是先将 订单持久化到表中,因为我们注释了订单关联用户的代码,所以Hibernate还是先插入空值,然后再根据我们的 用户关联订单 再来更新Orders表将 Customers_ID字段修改为正确的值!

这个时候我们发现,虽然这样可以,但还是会有一些问题,因为当数据量很大的时候,这样的操作是很占资源的,会影响性能,同时如果我们的数据库customers_ID字段定义为not null,非空,那么可想而知这种方式是不可行的!

那么可不可以将inverse=true加上,Customers将主动权交出后,我们仅仅用订单关联用户,而用户关联订单的注释掉呢?我们式式!

运行结果我们发现仅仅是将 用户添加到表中去了,而订单却丢失,这为什么,不是用户将主动权交出,而我们也用订单关联了用户,为何没有加入订单呢,首先要知道,关联是仅仅减缓到订单属于哪个用户,也就是关联订单的customers_ID字段!但用户类里,属性 Set orders = new HashSet();初始是为空的,这样虽然订单关联了用户,但用户对象内的orders属性还是为空,订单还没产生呢,这样Hibernate自然在保存用户的时候,判断集合为空,自然不会去添加订单!这个有点像什么呢,就好比腾讯的QQ宠物里面的所谓“超值大礼包”,每一种礼包我们可以认为是一个订单,而这样的“礼包”一产生也的属于对象,当然就是属于所有拥有QQ宠物的QQ号了!这可以认为上
订单关联了对象,但至于在操作对象的时候,订单有没有,这个其实还是由QQ号码决定的,看它要不要,它如果要了,就有订单,不要呢,当然就没订单了,虽然腾讯希望订单是属于他的!我个人觉得这个比如很恰当!

所以得出总结是:无论我们的Customer类是否将主动权交出去,我们都要将用户关系到订单!那可能会想:既然这样交不交主动权有什么区别呢?有!而且很大!就像我们一开始运行的效果。

如果我们将 用户主动权交出,通过监视的SQL我们可以看到只执行了三条SQL语句,分别说是插入用户和二条订单!没有更新!

而如果我们没有将Customers主动权交出的话,运行效果如下:

有五条语句,性能不一样,同时可以解决comstomers_ID字段不为空的问题!所以一般我们还是会选择交出主动权!

另外补充一下cascade的属性值:

<!--

none:在保存,更新或删除当前对象时,忽略其他关联的对象。它是cascade属性的默认值

save-update:当通过Session的save()以及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。

delete:当通过Session的delete()方法删除当前对象时,级联删除所有关联的对象。

all: 包含save-update以及delete的行为。此外,对当前对象执行evict()或lock()操作时,也会对所有关联的持久化对象执行evict()或lock()操作。

delete-orphan:删除所有和当前对象解除关联关系的对象。

all-delete-orphan:包含all和delete-orphan的行为

-->

时间: 2024-10-27 20:02:46

Hibernate 级联之OneToMany的相关文章

Hibernate级联关系OneToMany之 Annotation实现

[java] view plaincopy package com.lwp.hibernate.Model; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.G

hibernate级联处理问题

hibernate进行级联处理时,关于一对一的关系应该注意的问题. 1.假如有奖品项item和奖品aword,他们之间的对应关系是 1)item      1:1    aword 奖品项与奖品是一对一的关系,一个奖品项只能包含一个奖品. 2)aword   1:n    item 奖品与奖品项是一对多的关系,一个奖品可以出现在多个奖品项中. 2.在进行hibernate注解配置的时候,他们的关系应该如下: 1)entity   Item <span style="white-space:

hibernate 级联删除报更新失败的问题(org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update)

首先hibernate级联删除的前提是,首先需要在映射文件中配置,配置多表之间的关联关系: 下面以部门表(Dept)和员工表(Emp)为例: 1.在Emp.hbm.xml映射文件中配置many-to-one关系 1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http:/

hibernate级联保存,更新个人遇到的问题

在级联更新的时候,数据库中的数据是增加的,只是外键不存在,导致这样的问题产生的原因是,字表主键ID没有添加到集合中,导致Hibernate找不到子项而执行更新. hibernate级联保存,更新个人遇到的问题,布布扣,bubuko.com

hibernate级联保存问题

今天的遇到一个问题,搞了半天.做个记录 hibernate级联保存,设置了cascade关系,但新增时总是主表insert,从表update.以下为报错信息: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 网上的解释是id冲突导致的,即数据库中定义了id自增,而类被插入时也被赋予了id. 解决办法:将数据库id自增去掉,重新生成类文件,选择id自增策略选择i

hibernate级联

cascade和inverse (Employee – Department) Casade用来说明当对主对象进行某种操作时是否对其关联的从对象也作类似的操作,常用的cascade: none,all,save-update,delete, lock,refresh,evict,replicate,persist, merge,delete-orphan(one-to-many).一般对many-to-one,many-to-many不设置级联,在<one-to-one>和<one-to

Hibernate级联操作解密(inverse和cascade)

总结: Cascade:对级联操作进行限制,有如下几个参数: all : 所有情况下均进行关联操作.  none:所有情况下均不进行关联操作.这是默认值.  save-update:在执行save/update/saveOrUpdate时进行关联操作.  delete:在执行delete时进行关联操作. Inverse:在一对多模型中,只能在一的一方设置,inverse的作用就是在级联发生后,会再次更新子表数据的外键为主表的主键.确保子表外键不会为空. 下面演示一个班级学生的例子(一对多): 班

hibernate之实体@onetomany和@manytoone双向注解(转)

下面是User类: @onetomany @Entity @Table(name="user") public class User implements Serializable{ private static final long serialVersionUID = 6177417450707400228L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="id") priva

再谈Hibernate级联删除——JPA下的Hibernate实现一对多级联删除CascadeType.DELETE_ORPHAN

声明: 1.本文系原创,非抄袭或转载过来的. 2.本文论点都亲手做过实验论证. 3.本文所讲的Hibernate配置都基于注解的方式,hbm语法未提供. 非常多人对持久层概念搞不清JPA.Hibernate.EJB3.0的关系,这里做一下简单的说明:JPA是一个持久层设计接口,EJB3.0和Hibernate是详细的实现类,EJB3.0和Hibernate的功能近似相等的(Hibernate没有Session Bean,Spring MVC3的SessionAttribute跟Session B