Hibernate 一对多
表与表之间关系回顾(重点)
1 一对多
(1)分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类
(2)客户和联系人是一对多关系
- 客户:与公司有业务往来,百度、新浪、360
- 联系人:公司里面的员工,百度里面有很多员工,联系员工
** 公司和公司员工的关系
- 客户是一,联系人是多
- 一个客户里面有多个联系人,一个联系人只能属于一个客户
(3)一对多建表:通过外键建立关系
2 多对多
(1)订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单
(2)用户和角色多对多关系
- 用户: 小王、小马、小宋
- 角色:总经理、秘书、司机、保安
** 比如小王 可以 是总经理,可以是司机
** 比如小宋 可以是司机,可以是秘书,可以保安
** 比如小马 可以是 秘书,可以是总经理
- 一个用户里面可以有多个角色,一个角色里面可以有多个用户
(3)多对多建表:创建第三张表维护关系
3 一对一
(1)在中国,一个男人只能有一个妻子,一个女人只能有一个丈夫
Hibernate的一对多操作(重点)
一对多映射配置(重点)
以客户和联系人为例:客户是一,联系人是多
第一步 创建两个实体类,客户和联系人
第二步 让两个实体类之间互相表示
(1)在客户实体类里面表示多个联系人
- 一个客户里面有多个联系人
(2)在联系人实体类里面表示所属客户
- 一个联系人只能属于一个客户
第三步 配置映射关系
(1)一般一个实体类对应一个映射文件
(2)把映射最基本配置完成
(3)在映射文件中,配置一对多关系
- 在客户映射文件中,表示所有联系人
- 在联系人映射文件中,表示所属客户
第四步 创建核心配置文件,把映射文件引入到核心配置文件中
代码实践:
package org.model; import java.util.HashSet;
import java.util.Set; public class Customer {
private Integer cid;
private String cname;
private String tel;
//在一方创建多的集合 并且生成set get 方法
private Set<LinkMan> setlinkman=new HashSet<LinkMan>(); public Set<LinkMan> getSetlinkman() {
return setlinkman;
}
public void setSetlinkman(Set<LinkMan> setlinkman) {
this.setlinkman = setlinkman;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}
<?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="org.model.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="cname" column="cname"></property>
<property name="tel" column="tel"></property> <set name="setlinkman">
<!-- key中column的属性值为外键的名字 可随便写 作用指定外键 在多的一方添加外键 所以 根据class中的路径 在多方 创建的表中就会有clid字段 作为外键 -->
<key column="clid"></key>
<!-- class属性中写的是关联表实体类的名称 -->
<one-to-many class="org.model.LinkMan"/>
</set>
</class>
</hibernate-mapping>
package org.model; public class LinkMan {
private Integer lid;
private String lname;
private String tel;
//在多的一方 指定所属的客户 当然也可以只写一个字段(关联外键的id) 这里写的是一个对象
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 getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
}
<?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="org.model.LinkMan" table="t_linkman">
<id name="lid" column="lid">
<generator class="native"></generator>
</id>
<property name="lname" column="lname"></property>
<property name="tel" column="tel"></property>
<!-- name中写的是linkman表中关联对象的名称 column写的是外间的名称 class写的是关联对象的类的全路径 指定被关联的实体类-->
<many-to-one name="customer" column="clid" class="org.model.Customer"></many-to-one>
</class>
</hibernate-mapping>
核心配置文件
<?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>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">jay571018</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate3_demo1</property>
<!-- 第二步:配置Hibernate信息 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 设置数据库方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 设置与本地线程绑定session -->
<property name="hibernate.current_session_context_class">thread</property> <!-- 第三步:引入对象关系映射文件 -->
<mapping resource="org/model/Customer.hbm.xml"/>
<mapping resource="org/model/LinkMan.hbm.xml"/>
</session-factory>
</hibernate-configuration>
sessionfactory
package org.util; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; public class SessionFactoryUtils {
static Configuration configuration=null;
static SessionFactory sf=null; static{
configuration=new Configuration();
configuration.configure();//加载核心配置文件
sf=configuration.buildSessionFactory();
}
public static SessionFactory getsessionfactory(){
return sf;
} public static Session get(){
return sf.getCurrentSession();
} public static void main(String[] args){ } }
执行之后效果:
自动完成建表 并且在联系人表(多方)中添加了外键
一对多级联操作
级联操作
1 级联保存
(1)添加一个客户,为这个客户添加多个联系人
2 级联删除
(1)删除某一个客户,这个客户里面的所有的联系人也删除
一对多级联保存
1 添加客户,为这个客户添加一个联系人
(1)复杂写法:
//演示一对多级联保存
@Test
public void testAddDemo1() {
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("999"); LinkMan linkman = new LinkMan();
linkman.setLkm_name("lucy");
linkman.setLkm_gender("男");
linkman.setLkm_phone("911"); //2 在客户表示所有联系人,在联系人表示客户
// 建立客户对象和联系人对象关系
//2.1 把联系人对象 放到客户对象的set集合里面
customer.getSetLinkMan().add(linkman);
//2.2 把客户对象放到联系人里面
linkman.setCustomer(customer); //3 保存到数据库
session.save(customer);
session.save(linkman); //提交事务
tx.commit(); }catch(Exception e) {
tx.rollback();
}finally {
session.close();
//sessionFactory不需要关闭
sessionFactory.close();
}
}
执行效果:
(2)简化写法
- 一般根据客户添加联系人
第一步 在客户映射文件中进行配置
- 在客户映射文件里面set标签进行配置
第二步 创建客户和联系人对象,只需要把联系人放到客户里面就可以了,最终只需要保存客户就可以了
//演示一对多级联保存
@Test
public void testAddDemo2() {
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("110");
customer.setCustMobile("999"); LinkMan linkman = new LinkMan();
linkman.setLkm_name("小宏");
linkman.setLkm_gender("男");
linkman.setLkm_phone("911");
//2 把联系人放到客户里面
customer.getSetLinkMan().add(linkman);
//3 保存客户
session.save(customer); //提交事务
tx.commit();
}catch(Exception e) {
tx.rollback();
}finally {
session.close();
//sessionFactory不需要关闭
sessionFactory.close();
}
}
代码实践:
修改customer配置文件
<?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="org.model.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="cname" column="cname"></property>
<property name="tel" column="tel"></property> <set name="setlinkman" cascade="save-update">
<!-- key中column的属性值为外键的名字 可随便写 作用指定外键 在多的一方添加外键 所以 根据class中的路径 在多方 创建的表中就会有clid字段 作为外键 -->
<key column="clid"></key>
<!-- class属性中写的是关联表实体类的名称 -->
<one-to-many class="org.model.LinkMan"/>
</set>
</class>
</hibernate-mapping>
package org.testdemo; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;
import org.model.Customer;
import org.model.LinkMan;
import org.util.SessionFactoryUtils; public class OnetoMany {
@Test
public void test1(){
//复杂写法 没有配置cascade属性
Session session=null;
Transaction tran=null;
try{
session=SessionFactoryUtils.get();
//开启事务
tran=session.beginTransaction(); Customer c=new Customer();
c.setCname("阿里");
c.setTel("0379-1534350"); LinkMan l=new LinkMan();
l.setLname("马云");
l.setTel("15035286558"); //分别建立联系
c.getSetlinkman().add(l);
l.setCustomer(c);
//然后分别保存
session.save(c);
session.save(l); //提交事务
tran.commit(); }catch(Exception e){
e.printStackTrace();
}finally{
} }
@Test
public void test2(){
//简单写法 在客户映射文件中配置cascade属性 因为联系人表的外键 约束与客户表的主键 所以一般都是先保存客户表 所以在客户表中进行配置
Session session=null;
Transaction tran=null;
try{
session=SessionFactoryUtils.get();
//开启事务
tran=session.beginTransaction(); Customer c=new Customer();
c.setCname("百度");
c.setTel("0379-1534350"); LinkMan l=new LinkMan();
l.setLname("李彦宏");
l.setTel("15035286558"); //不需要分别建立联系
// c.getSetlinkman().add(l);
// l.setCustomer(c);
//因为客户表是主控方 只需要在客户对象中关联 联系人表的对象即可
//然后分别保存
// session.save(c);
// session.save(l);
c.getSetlinkman().add(l);
session.save(c); //提交事务
tran.commit(); }catch(Exception e){
e.printStackTrace();
}finally{
} }
}
执行效果:
一对多级联删除
1 删除某个客户,把客户里面所有的联系人删除
2 具体实现
第一步 在客户(主控方)映射文件set标签,进行配置
(1)使用属性cascade属性值 delete
第二步 在代码中直接删除客户
(1)根据id查询对象,调用session里面delete方法删除
3 执行过程:
(1)根据id查询客户
(2)根据外键id值查询联系人
(3)把联系人外键设置为null
(4)删除联系人和客户
代码实践:
@Test
public void test3(){
//进行级联删除操作 需要在主控方set标签中增加属性配置
Session session=null;
Transaction tran=null;
try{
session=SessionFactoryUtils.get();
//开启事务
tran=session.beginTransaction();
//A级联删除删除的是主控方的对象 从而把依赖的对象也删除 联系人表的外键依赖于客户表中的主键
Customer c=session.get(Customer.class,4);
session.delete(c);
//B下面这种方式不会级联删除 执行之后只会删掉联系人表中对应的记录 而客户表不会删
// LinkMan l=session.get(LinkMan.class,5);//
// session.delete(l);
tran.commit(); }catch(Exception e){
e.printStackTrace();
}finally{
}
}
删除之前:
A代码 级联删除之后:
执行控制台打印 删除过程
Hibernate:
select
customer0_.cid as cid1_0_0_,
customer0_.cname as cname2_0_0_,
customer0_.tel as tel3_0_0_
from
t_customer customer0_
where
customer0_.cid=?
Hibernate:
select
setlinkman0_.clid as clid4_1_0_,
setlinkman0_.lid as lid1_1_0_,
setlinkman0_.lid as lid1_1_1_,
setlinkman0_.lname as lname2_1_1_,
setlinkman0_.tel as tel3_1_1_,
setlinkman0_.clid as clid4_1_1_
from
t_linkman setlinkman0_
where
setlinkman0_.clid=?
Hibernate:
update
t_linkman
set
clid=null
where
clid=?
Hibernate:
delete
from
t_linkman
where
lid=?
Hibernate:
delete
from
t_customer
where
cid=?
B代码 删除之后:
删除过程:
Hibernate:
select
linkman0_.lid as lid1_1_0_,
linkman0_.lname as lname2_1_0_,
linkman0_.tel as tel3_1_0_,
linkman0_.clid as clid4_1_0_
from
t_linkman linkman0_
where
linkman0_.lid=?
Hibernate:
delete
from
t_linkman
where
lid=?
一对多修改操作(inverse属性)
1 让lucy联系人所属客户不是传智播客,而是百度
2 inverse属性
(1)因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户时候修改一次外键,修改联系人时候也修改一次外键,造成效率问题
(2)解决方式:让其中的一方不维护外键
- 一对多里面,让其中一方放弃外键维护
- 一个国家有总统,国家有很多人,总统不能认识国家所有人,国家所有人可以认识总统
(3)具体实现:
在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
代码实现:
操作之前:
操作之后:
测试代码:
@Test
public void test4(){
Session session=null;
Transaction tran=null;
try{
session=SessionFactoryUtils.get();
//开启事务
tran=session.beginTransaction();
Customer al=session.get(Customer.class,2);
LinkMan linkman=session.get(LinkMan.class,111);
al.getSetlinkman().add(linkman);
linkman.setCustomer(al);//因为是持久态对象 所以不需要进行save保存 当事务提交的时候 会自动进行保存 tran.commit(); }catch(Exception e){
e.printStackTrace();
}finally{
}
}
没有添加inverse属性执行过程:
Hibernate:
select
customer0_.cid as cid1_0_0_,
customer0_.cname as cname2_0_0_,
customer0_.tel as tel3_0_0_
from
t_customer customer0_
where
customer0_.cid=?
Hibernate:
select
linkman0_.lid as lid1_1_0_,
linkman0_.lname as lname2_1_0_,
linkman0_.tel as tel3_1_0_,
linkman0_.clid as clid4_1_0_
from
t_linkman linkman0_
where
linkman0_.lid=?
Hibernate:
select
setlinkman0_.clid as clid4_1_0_,
setlinkman0_.lid as lid1_1_0_,
setlinkman0_.lid as lid1_1_1_,
setlinkman0_.lname as lname2_1_1_,
setlinkman0_.tel as tel3_1_1_,
setlinkman0_.clid as clid4_1_1_
from
t_linkman setlinkman0_
where
setlinkman0_.clid=?
Hibernate:
update
t_linkman
set
lname=?,
tel=?,
clid=?
where
lid=?
Hibernate:
update
t_linkman
set
clid=?
where
lid=?
多了一次更新
现在在一方set表签中添加inverse属性 让它放弃表的维护工作
<?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="org.model.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="cname" column="cname"></property>
<property name="tel" column="tel"></property>
<!-- 默认值是false 不放弃维护 这里设置为false 表示放弃维护 -->
<set name="setlinkman" cascade="save-update,delete" inverse="true">
<!-- key中column的属性值为外键的名字 可随便写 作用指定外键 在多的一方添加外键 所以 根据class中的路径 在多方 创建的表中就会有clid字段 作为外键 -->
<key column="clid"></key>
<!-- class属性中写的是关联表实体类的名称 -->
<one-to-many class="org.model.LinkMan"/>
</set>
</class>
</hibernate-mapping>
执行代码观察控制台:
Hibernate:
select
customer0_.cid as cid1_0_0_,
customer0_.cname as cname2_0_0_,
customer0_.tel as tel3_0_0_
from
t_customer customer0_
where
customer0_.cid=?
Hibernate:
select
linkman0_.lid as lid1_1_0_,
linkman0_.lname as lname2_1_0_,
linkman0_.tel as tel3_1_0_,
linkman0_.clid as clid4_1_0_
from
t_linkman linkman0_
where
linkman0_.lid=?
Hibernate:
select
setlinkman0_.clid as clid4_1_0_,
setlinkman0_.lid as lid1_1_0_,
setlinkman0_.lid as lid1_1_1_,
setlinkman0_.lname as lname2_1_1_,
setlinkman0_.tel as tel3_1_1_,
setlinkman0_.clid as clid4_1_1_
from
t_linkman setlinkman0_
where
setlinkman0_.clid=?
Hibernate:
update
t_linkman
set
lname=?,
tel=?,
clid=?
where
lid=?
少了一次更新的语句,性能提高
Hibernate 一对多的更多相关文章
- Hibernate一对多配置
刚刚学习了Hibernate框架的基础知识,下面我来说说关于Hibernate一对多的配置 首先是大配置 连接数据库 用户名 和密码 能和小配置连接 部门小配置: 员工小配置: 部门实体类 员工实体类 ...
- hibernate 一对多双向关联 详解
一.解析: 1. 一对多双向关联也就是说,在加载班级时,能够知道这个班级所有的学生. 同时,在加载学生时,也能够知道这个学生所在的班级. 2.我们知道,一对多关联映射和多对一关联映射是一样的,都是在 ...
- Hibernate一对多OnetoMany
------------------------Hibernate一对多OnetoMany 要点: 配置在一端. 1.如果是单向关联,即只在一端配置OneToMany,多端不配置ManyToOne.则 ...
- Hibernate一对多单向关联和双向关联映射方法及其优缺点 (待续)
一对多关联映射和多对一关联映射实现的基本原理都是一样的,既是在多的一端加入一个外键指向一的一端外键,而主要的区别就是维护端不同.它们的区别在于维护的关系不同: 一对多关联映射是指在加载一的一端数据的同 ...
- Hibernate一对多操作
--------------------siwuxie095 Hibernate 一对多操作 以客户和联系人为例,客户是一,联系人是多 即 一个客户里面有多个联系人,一个联系人只能属于一个客户 注意: ...
- Java进阶知识10 Hibernate一对多_多对一双向关联(Annotation+XML实现)
本文知识点(目录): 1.Annotation 注解版(只是测试建表) 2.XML版 的实现(只是测试建表) 3.附录(Annotation 注解版CRUD操作)[注解版有个问题:插入值时 ...
- Java进阶知识09 Hibernate一对多单向关联(Annotation+XML实现)
1.Annotation 注解版 1.1.在一的一方加Set 1.2.创建Customer类和Order类 package com.shore.model; import java.util.Hash ...
- Hibernate—— 一对多 和 多对多关联关系映射(xml和注解)总结(转载)
One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XML/Annotation) 懒加载和积极加载 一对多双向外键关联(XML/Annotati ...
- Hibernate一对多(多对一)关联关系
上一篇博文总结了 Hibernate 的一对一的关联关系, 包括基于主键的单向一对一, 基于外键的单向一对一, 基于外键的双向一对一. 下面咱们说一下 Hibernate 的一对多关联关系. 其实一对 ...
- 菜鸟学习Hibernate——一对多关系映射
Hibernate中的关系映射,最常见的关系映射之一就是一对多关系映射例如学生与班级的关系,一个班级对应多个学生.如图: Hibernate中如何来映射这两个的关系呢? 下面就为大家讲解一下: 1.创 ...
随机推荐
- 自己定义控件三部曲之动画篇(七)——ObjectAnimator基本使用
前言: 假如生活欺骗了你, 不要悲伤,不要心急! 忧郁的日子里须要镇静: 相信吧,快乐的日子终将会来临! 心儿永远向往着未来: 如今却常是忧郁. 一切都是瞬息,一切都将会过去: 而那过去了的,就会成为 ...
- root用户不能改动iptables
需求:因为防火墙做了IP和port限制,如今须要加入一条规则使之能够訪问指定的IP和port. vi /etc/sysconfig/iptables, 加入完毕后,wq保存,提示文件仅仅读无法保存.! ...
- 关于SharePoint讨论板的一些知识(2)--视图中的栏目
关于SharePoint讨论板的一些知识(2)--视图中的栏目 新建讨论后,默认显示四个栏目:主题.创建者.答复和上次更新时间. 从功能区的当前视图能够看出这是默认的主 ...
- Java图形界面(GUI)——如何将JTable成功放入面板
在这次课程设计中,大部分内容都设计的很流畅,没有遇到太大的问题,但在面板中加入JTable时确实花费了一部分时间,在此将解决办法总结出来: 定义控件: JPanel panel = new JPane ...
- EOJ 2847 路由结点
数学知识 凸N边形的对角线条数为:n(n-3)/2因为每一个交点对应两条对角线,而两条对角线又对应着一个四边形.于是焦点个数就对应四边形的个数.问题转化成由凸n边形的n个顶点取4个顶点可组成多少个四边 ...
- Windows下配置SVN服务器
2013-09-03 21:40:34 1. 下载安装svn软件 1.1 服务端svn 下载地址:http://subversion.apache.org/packages.html 默认安装路径:D ...
- mvc 伪静态任意扩展名的实现方法
比如:要实现 http://localhost:60291/home/geta/1212.html 或者 .abc 任意扩展名 完成两步即可. 第一步修改路由: public static void ...
- Codeforces Round #446
Greed #include<stdio.h> #include<string.h> #include<stdlib.h> #include<vector&g ...
- android反编译查看源码,apk解压后XML乱码解决
1:找了好几个软件都不能图形化的解决反编译,很不舒服,最后找了个还算顺手的,顺便保存下. 2:使用过程 <1> apk转jar apktoolkit工具 <2> 查看jar源码 ...
- hdu 2444 The Accomodation of Students 判断是否构成二分图 + 最大匹配
此题就是求最大匹配.不过需要判断是否构成二分图.判断的方法是人选一点标记为红色(0),与它相邻的点标记为黑色(1),产生矛盾就无法构成二分图.声明一个vis[],初始化为-1.通过深搜,相邻的点不满足 ...