首页 > 代码库 > Hibernate一对多操作

Hibernate一对多操作

--------------------siwuxie095

   

   

   

   

   

   

   

   

Hibernate 一对多操作

   

   

以客户和联系人为例,客户是一,联系人是多

   

一个客户里面有多个联系人,一个联系人只能属于一个客户

   

注意:这里的客户是公司级的,即 公司,联系人 公司里的员工

   

   

   

   

(一)一对多映射配置

   

   

第一步:创建两个实体类,客户和联系人

   

   

   

   

第二步:让两个实体类之间互相表示

   

1)在客户实体类中表示多个联系人

   

技术分享

   

   

2)在联系人实体类中表示所属客户

   

技术分享

   

   

   

   

第三步:配置映射关系

   

「一般一个实体类对应一个映射配置文件」

   

1)配置基本的映射

   

   

2)配置关联关系的映射(一对多关系

   

1)在客户的映射配置文件中,表示所有联系人

   

技术分享

   

   

2)在联系人的映射配置文件中,表示所属客户

   

技术分享

   

   

   

   

第四步:在核心配置文件中引入映射配置文件

   

技术分享

   

   

   

   

   

   

   

(二)一对多级联保存

   

如:添加客户,为这个客户添加一个联系人

   

1)复杂写法

   

/**

* 一对多级联保存的复杂写法

*

*

* 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 jar 包)

*

* 选中方法名,右键->Run As->JUint Test

*/

@Test

public void testSave(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//添加一个客户,为这个客户添加一个联系人

 

//(1)

//创建客户和联系人对象

Customer customer=new Customer();

customer.setCustName("百度");

customer.setCustLevel("VIP");

customer.setCustSource("网络");

customer.setCustPhone("110");

customer.setCustMobile("114");

 

LinkMan linkMan=new LinkMan();

linkMan.setLkmName("小明");

linkMan.setLkmGender("");

linkMan.setLkmPhone("111");

 

//(2)

//建立客户对象和联系人对象的关系

//

//在客户实体类中表示联系人,在联系人实体类中表示客户

//

//具体:

//把联系人对象放到客户对象的 Set 集合中

//把客户对象放到联系人对象中

customer.getLinkManSet().add(linkMan);

linkMan.setCustomer(customer);

 

//(3)

//保存到数据库(级联保存)

session.save(customer);

session.save(linkMan);

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

   

   

   

2)简化写法

   

先在客户的映射配置文件中的 set 标签添加 cascade 属性,并

将其值设置为 save-update,再进行具体实现

   

技术分享

   

/**

* 一对多级联保存的简化写法

*

* 在客户的映射配置文件中的 set 标签

* 添加 cascade 属性,并将其值设置为

* save-update

*/

@Test

public void testSaveX(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//添加一个客户,为这个客户添加一个联系人

 

//(1)

//创建客户和联系人对象

Customer customer=new Customer();

customer.setCustName("谷歌");

customer.setCustLevel("普通");

customer.setCustSource("网络");

customer.setCustPhone("911");

customer.setCustMobile("995");

 

LinkMan linkMan=new LinkMan();

linkMan.setLkmName("小强");

linkMan.setLkmGender("");

linkMan.setLkmPhone("999");

 

//(2)

//建立客户对象和联系人对象的关系

//

//在客户实体类中表示联系人

//

//具体:

//把联系人对象放到客户对象的 Set 集合中

customer.getLinkManSet().add(linkMan);

 

//(3)

//保存到数据库(级联保存)

session.save(customer);

 

 

//简化所在:不用把客户对象放到联系人对象

//中,且最后不用保存联系人对象

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

   

   

   

   

   

   

   

(三)一对多级联删除

   

如:删除某个客户,把客户里面的所有联系人都删除

   

1)具体写法

   

先在客户的映射配置文件中的 set 标签添加 cascade 属性,并

将其值设置为 delete,再进行具体实现

   

技术分享

   

/**

* 一对多级联删除

*

* 在客户的映射配置文件中的 set 标签

* 添加 cascade 属性,并将其值设置为

* delete

*/

@Test

public void testDelete(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//除一个客户,并将这个客户中的所有联系人删除

 

//(1)

//根据 id 查询客户对象

Customer customer=session.get(Customer.class, 1);

 

//(2)

//调用 Session delete() 方法实现级联删除

session.delete(customer);

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

   

   

   

2)执行过程

   

1)根据 id 查询客户

   

2)根据外键 id 值查询联系人

   

3)把联系人外键设置为 null

   

4)删除联系人和客户

   

   

   

   

   

   

(四)一对多修改

   

如:让某联系人不再属于原客户,而属于新客户

   

(1)主要问题

   

因为 Hibernate 双向维护外键,即 在客户和联系人中都要配置外键

   

所以在修改客户时会修改一次外键,修改联系人时也会修改一次外键,

也就是说产生了多余的 sql 语句,使得效率低下

   

   

   

(2)解决方式

   

修改中,让其中一方放弃外键维护,一般是让的一方放弃

   

   

   

(3)具体写法

   

先在客户的映射配置文件中的 set 标签添加 inverse 属性,并

将其值设置为 true,再进行具体实现

   

技术分享

   

/**

* 一对多修改

*

* 在客户的映射配置文件中的 set 标签

* 添加 inverse 属性,并将其值设置为

* true

*/

@Test

public void testUpdate(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//在百度工作的小明跳槽到谷歌,修改联系人表中对应的外键

 

//(1)

//根据 id 分别查询客户(谷歌)和联系人(小明)

Customer customer=session.get(Customer.class, 2);

LinkMan linkMan=session.get(LinkMan.class, 1);

 

//(2)

//设置持久态对象的值:

//1)把联系人对象放到客户对象的 Set 集合中

//2)把客户对象放到联系人对象中

customer.getLinkManSet().add(linkMan);

linkMan.setCustomer(customer);

 

//持久态对象可以自动更新数据库,所以下面的代码不用写

//session.update(customer);

//session.update(linkMan);

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

   

   

   

   

   

   

   

工程结构目录如下:

   

技术分享

   

   

   

HibernateUtils.java:

   

package com.siwuxie095.utils;

   

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

   

public class HibernateUtils {

 

static Configuration cfg=null;

static SessionFactory sessionFactory=null;

 

//或: 加上 private final 亦可,不过此时不能等于 null

// private static final Configuration cfg;

// private static final SessionFactory sessionFactory;

 

//静态代码块

static {

//加载核心配置文件

cfg=new Configuration();

cfg.configure();

sessionFactory=cfg.buildSessionFactory();

 

}

 

//提供方法返回 sessionFactory

public static SessionFactory getSessionFactory() {

return sessionFactory;

}

 

 

//提供方法返回与本地线程绑定的 Session

public static Session getCurrentSession() {

return sessionFactory.getCurrentSession();

}

 

}

   

   

   

Customer.java:

   

package com.siwuxie095.entity;

   

import java.util.HashSet;

import java.util.Set;

   

//客户实体类(客户是公司级的)

public class Customer {

 

 

private Integer cid; //客户 id

private String custName; //客户名称

private String custLevel; //客户级别

private String custSource; //客户来源

private String custPhone; //客户电话

private String custMobile; //客户手机

 

//在客户实体类中表示多个联系人,即 一个客户里面有多个联系人

//

//Hibernate 中要求使用 Set 集合表示"多"的数据

private Set<LinkMan> linkManSet=new HashSet<LinkMan>();

 

 

public Set<LinkMan> getLinkManSet() {

return linkManSet;

}

public void setLinkManSet(Set<LinkMan> linkManSet) {

this.linkManSet = linkManSet;

}

 

public Integer getCid() {

return cid;

}

public void setCid(Integer cid) {

this.cid = cid;

}

 

public String getCustName() {

return custName;

}

public void setCustName(String custName) {

this.custName = custName;

}

 

public String getCustLevel() {

return custLevel;

}

public void setCustLevel(String custLevel) {

this.custLevel = custLevel;

}

 

public String getCustSource() {

return custSource;

}

public void setCustSource(String custSource) {

this.custSource = custSource;

}

 

public String getCustPhone() {

return custPhone;

}

public void setCustPhone(String custPhone) {

this.custPhone = custPhone;

}

 

public String getCustMobile() {

return custMobile;

}

public void setCustMobile(String custMobile) {

this.custMobile = custMobile;

}

 

}

   

   

   

LinkMan.java:

   

package com.siwuxie095.entity;

   

   

//联系人实体类

public class LinkMan {

   

private Integer lid; // 联系人 id

private String lkmName; // 联系人姓名

private String lkmGender; // 联系人性别

private String lkmPhone; // 联系人电话

 

//在联系人实体类中表示所属客户,即 一个联系人只能属于一个客户

private Customer customer;

 

 

public Customer getCustomer() {

return customer;

}

public void setCustomer(Customer customer) {

this.customer = customer;

}

 

public Integer getLid() {

return lid;

}

public void setLid(Integer lid) {

this.lid = lid;

}

 

public String getLkmName() {

return lkmName;

}

public void setLkmName(String lkmName) {

this.lkmName = lkmName;

}

 

public String getLkmGender() {

return lkmGender;

}

public void setLkmGender(String lkmGender) {

this.lkmGender = lkmGender;

}

 

public String getLkmPhone() {

return lkmPhone;

}

public void setLkmPhone(String lkmPhone) {

this.lkmPhone = lkmPhone;

}

 

}

   

   

   

HibernateOneToMany.java:

   

package com.siwuxie095.hibernatetest;

   

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.junit.Test;

   

import com.siwuxie095.entity.Customer;

import com.siwuxie095.entity.LinkMan;

import com.siwuxie095.utils.HibernateUtils;

   

   

//一对多操作

public class HibernateOneToMany {

 

 

/**

* 一对多级联保存的复杂写法

*

*

* 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 jar 包)

*

* 选中方法名,右键->Run As->JUint Test

*/

@Test

public void testSave(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//添加一个客户,为这个客户添加一个联系人

 

//(1)

//创建客户和联系人对象

Customer customer=new Customer();

customer.setCustName("百度");

customer.setCustLevel("VIP");

customer.setCustSource("网络");

customer.setCustPhone("110");

customer.setCustMobile("114");

 

LinkMan linkMan=new LinkMan();

linkMan.setLkmName("小明");

linkMan.setLkmGender("");

linkMan.setLkmPhone("111");

 

//(2)

//建立客户对象和联系人对象的关系

//

//在客户实体类中表示联系人,在联系人实体类中表示客户

//

//具体:

//把联系人对象放到客户对象的 Set 集合中

//把客户对象放到联系人对象中

customer.getLinkManSet().add(linkMan);

linkMan.setCustomer(customer);

 

//(3)

//保存到数据库(级联保存)

session.save(customer);

session.save(linkMan);

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

 

 

/**

* 一对多级联保存的简化写法

*

* 在客户的映射配置文件中的 set 标签

* 添加 cascade 属性,并将其值设置为

* save-update

*/

@Test

public void testSaveX(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//添加一个客户,为这个客户添加一个联系人

 

//(1)

//创建客户和联系人对象

Customer customer=new Customer();

customer.setCustName("谷歌");

customer.setCustLevel("普通");

customer.setCustSource("网络");

customer.setCustPhone("911");

customer.setCustMobile("995");

 

LinkMan linkMan=new LinkMan();

linkMan.setLkmName("小强");

linkMan.setLkmGender("");

linkMan.setLkmPhone("999");

 

//(2)

//建立客户对象和联系人对象的关系

//

//在客户实体类中表示联系人

//

//具体:

//把联系人对象放到客户对象的 Set 集合中

customer.getLinkManSet().add(linkMan);

 

//(3)

//保存到数据库(级联保存)

session.save(customer);

 

 

//简化所在:不用把客户对象放到联系人对象

//中,且最后不用保存联系人对象

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

 

 

 

/**

* 一对多级联删除

*

* 在客户的映射配置文件中的 set 标签

* 添加 cascade 属性,并将其值设置为

* delete

*/

@Test

public void testDelete(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//删除一个客户,并将这个客户中的所有联系人删除

 

//(1)

//根据 id 查询客户对象

Customer customer=session.get(Customer.class, 1);

 

//(2)

//调用 Session delete() 方法实现级联删除

session.delete(customer);

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

 

 

/**

* 一对多修改

*

* 在客户的映射配置文件中的 set 标签

* 添加 inverse 属性,并将其值设置为

* true

*/

@Test

public void testUpdate(){

 

SessionFactory sessionFactory=null;

Session session=null;

Transaction tx=null;

 

try {

//得到 SessionFactory 对象

sessionFactory=HibernateUtils.getSessionFactory();

//创建 Session 对象

session=sessionFactory.openSession();

//开启事务

tx=session.beginTransaction();

 

//在百度工作的小明跳槽到谷歌,修改联系人表中对应的外键

 

//(1)

//根据 id 分别查询客户(谷歌)和联系人(小明)

Customer customer=session.get(Customer.class, 2);

LinkMan linkMan=session.get(LinkMan.class, 1);

 

//(2)

//设置持久态对象的值:

//1)把联系人对象放到客户对象的 Set 集合中

//2)把客户对象放到联系人对象中

customer.getLinkManSet().add(linkMan);

linkMan.setCustomer(customer);

 

//持久态对象可以自动更新数据库,所以下面的代码不用写

//session.update(customer);

//session.update(linkMan);

 

 

//提交事务

tx.commit();

} catch (Exception e) {

//回滚事务

tx.rollback();

} finally {

//关闭资源

session.close();

sessionFactory.close();

}

}

}

   

   

   

Customer.hbm.xml:

   

<?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>

   

<!--

(1)

class 标签:配置实体类和数据库表的对应;

name 属性:实体类的全路径,即 全限定名;

table 属性:数据库表的名称(数据库表由 Hibernate 自动生成)

-->

<class name="com.siwuxie095.entity.Customer" table="t_customer">

 

<!--

(2)

id 标签:配置实体类 id 和表 id 对应(主键);

name 属性:实体类里 id 属性名称;

column 属性:生成表中 id 字段名称

-->

<id name="cid" column="cid">

<!-- native:设置主键 id 自动增长 -->

<generator class="native"></generator>

</id>

 

<!--

(3)

property 标签:配置其它属性和表中字段对应;

name 属性:实体类属性名称;

column 属性:生成表中字段名称

-->

<property name="custName" column="cust_name"></property>

<property name="custLevel" column="cust_level"></property>

<property name="custSource" column="cust_source"></property>

<property name="custPhone" column="cust_phone"></property>

<property name="custMobile" column="cust_mobile"></property>

 

<!--

(4)

set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合;

name 属性:"多"的一方的对象的 Set 集合的名称(在客户实体类中声明);

cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开);

inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false

 

注意:inverse="true" 主要用于修改操作,防止产生多余的 sql 语句,但如果

同时配置了 cascade="save-update" inverse="true",将会导致在级联保存

操作后,没有外键(为 null

-->

<set name="linkManSet" cascade="save-update,delete" inverse="true">

 

<!--

一对多建表,有外键。Hibernate 的机制

是双向维护外键(即 都配置外键)

 

key 标签:配置"多"的一方的外键

column 属性:"多"的一方的外键名称

-->

<key column="clid"></key>

 

<!--

one-to-many 标签:配置实体类的一对多关联

class 属性:"多"的一方的类的全路径,即 联系人实体类的全限定名

-->

<one-to-many class="com.siwuxie095.entity.LinkMan"/>

</set>

 

</class>

</hibernate-mapping>

   

   

   

LinkMan.hbm.xml:

   

<?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="com.siwuxie095.entity.LinkMan" table="t_linkman">

 

<id name="lid" column="lid">

<generator class="native"></generator>

</id>

 

<property name="lkmName" column="lkm_name"></property>

<property name="lkmGender" column="lkm_gender"></property>

<property name="lkmPhone" column="lkm_phone"></property>

 

 

<!-- 配置关联关系的映射(配置关联对象) -->

 

<!--

many-to-one 标签:配置实体类的多对一关联;

name 属性:"一"的一方的对象的名称(在联系人实体类中声明);

class 属性:"一"的一方的类的全路径,即 客户实体类的全限定名;

column 属性:表中的外键名称

-->

<many-to-one name="customer" class="com.siwuxie095.entity.Customer" column="clid"></many-to-one>

 

</class>

</hibernate-mapping>

   

   

   

hibernate.cfg.xml:

   

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

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

 

<!-- 第一部分:配置数据库信息(必须) -->

 

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<!-- 或使用 jdbc:mysql:///hibernate_db 代替,省略 localhost:3306 -->

<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password">8888</property>

 

 

 

<!-- 第二部分:配置 Hibernate 信息(可选) -->

 

<!-- 输出底层 sql 语句 -->

<property name="hibernate.show_sql">true</property>

<!-- 输出底层 sql 语句格式 -->

<property name="hibernate.format_sql">true</property>

<!--

Hibernate 帮助创建表,不是自动创建,而需要配置之后。

update:如果已经有表,就更新,如果没有,就自动创建

-->

<property name="hibernate.hbm2ddl.auto">update</property>

<!--

配置数据库方言,让 Hibernate 框架识别不同数据库自己特有的语句

如:在 MySQL 中实现分页的关键字 limit,只能在 MySQL 中使用,而

Oracle 中实现分页的关键字则是 rownum

-->

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 配置 Session 绑定本地线程 -->

<property name="hibernate.current_session_context_class">thread</property>

 

 

 

<!-- 第三部分:引入映射配置文件,把映射配置文件放到核心配置文件(必须) -->

 

<mapping resource="com/siwuxie095/entity/Customer.hbm.xml"/>

<mapping resource="com/siwuxie095/entity/LinkMan.hbm.xml"/>

 

</session-factory>

</hibernate-configuration>

   

   

   

   

   

   

   

   

   

【made by siwuxie095】

Hibernate一对多操作