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一对多操作的更多相关文章
- hibernate 一对多操作(级联操作)
一对多级联操作 1. 级联保存 复杂写法 Company company = new Company(); company.setcName("Hello"); company. ...
- Hibernate_day03--课程安排_表之间关系_一对多操作
Hibernate_day03 上节内容 今天内容 表与表之间关系回顾(重点) Hibernate的一对多操作(重点) 一对多映射配置(重点) 一对多级联操作 一对多级联保存 一对多级联删除 一对多修 ...
- hibernate 一对多双向关联 详解
一.解析: 1. 一对多双向关联也就是说,在加载班级时,能够知道这个班级所有的学生. 同时,在加载学生时,也能够知道这个学生所在的班级. 2.我们知道,一对多关联映射和多对一关联映射是一样的,都是在 ...
- Hibernate一对多OnetoMany
------------------------Hibernate一对多OnetoMany 要点: 配置在一端. 1.如果是单向关联,即只在一端配置OneToMany,多端不配置ManyToOne.则 ...
- Hibernate一对多单向关联和双向关联映射方法及其优缺点 (待续)
一对多关联映射和多对一关联映射实现的基本原理都是一样的,既是在多的一端加入一个外键指向一的一端外键,而主要的区别就是维护端不同.它们的区别在于维护的关系不同: 一对多关联映射是指在加载一的一端数据的同 ...
- Hibernate 一对多
表与表之间关系回顾(重点) 1 一对多 (1)分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类 (2)客户和联系人是一对多关系 - 客户:与公司有业务往来,百度.新浪.360 - 联系 ...
- Hibernate的数据操作(4.*以上版本)
Hibernate的基本数据操作 适用于4.* ..sessionFactory的创建区别 public class NewsTest { private Session session = null ...
- Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)
本文知识点(目录): 1.Annotation 注解版(只是测试建表) 2.XML版 的实现(只是测试建表) 3.附录(Annotation 注解版CRUD操作)[注解版有个问题:插入值时 ...
- 六 Hibernate多表操作&级联&外键维护
Hibernate的一对多关联映射 Hibernate的多对多关联映射 数据库表与表之间的关系:一对多,多对多,一对一 一对多:一个部门对应多个员工,一个员工只能属于一个部门.一个客户对应多个联系人, ...
随机推荐
- 【转】Linux 静态库与共享库的使用
原文网址:http://blog.csdn.net/heyabo/article/details/11688517 申明: 正如题如示,本篇讲的是Linux下是静态库与共享库,而Window下的动态链 ...
- JavaScript模块化-require.js,r.js和打包发布
在JavaScript模块化和闭包和JavaScript-Module-Pattern-In-Depth这两篇文章中,提到了模块化的基本思想,但是在实际项目中模块化和项目人员的分工,组建化开发,打包发 ...
- Eclipse下无法解析注解:@Getter和@Setter
接触到一个项目,java bean全部使用@Getter和@Setter来偷懒,我用getXXX方法,结果发现编译失败,没法用.后来看到另一个项目也是用了@Getter和@Setter注解,但人家用的 ...
- Unit01: Servlet基础 、 HTTP协议
Unit01: Servlet基础 . HTTP协议 在页面上输出当前时间 package web; import java.io.IOException; import java.io.PrintW ...
- Unit01: jQuery概述 、 jQuery选择器 、 jQuery操作DOM
Unit01: jQuery概述 . jQuery选择器 . jQuery操作DOM 使用jQuery放大字体: <!DOCTYPE html> <html> <head ...
- 561. 数组拆分 I
题目 python class Solution: def arrayPairSum(self, nums): """ :type nums: List[int] :rt ...
- JAVA多线程三种实现方式
JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...
- java代码---indexOf()方法
总结:indexOf(String str,int index)方法.从参数指定位置开始,如果index值超过了字符串长度,则返回-1 package com.a.b; import java.io. ...
- 20165226 MySort的实现
MySort的实现 一.实验要求 研究sort的其他功能,要能改的动代码,模拟实现Linux下Sort -t : -k 2的功能. 二.代码 /** * Created by xiang on 201 ...
- [转]加密经验集 => C#
下载地址 代码摘自 C#高级编程(第7版) 第579页 不对称加密