一对一的关联就不写了,一般项目也用不到,如果可以一对一就直接合成一个表了,也不会出现一对一的关系。

本文主要研究一对多的关系。

1.一对多的关系研究:

(1)RDB中关系表达:  多的一方创建外键指向一的一方的主键

 (2)Java实体中的表达:  在一的一方创建Set集合维护多的一方,在多的一方创建单个一的一方的对象的引用。

也可以更深入的理解为:

    

(3)ORM元数据中表达: (XXX.hbm.xml中的配置)

  • 一的一方的配置(Customer)

      

  • 多的一方的配置(LinkMan)

      

2.关联操作

  顾客和联系人是一对多的关系,一个顾客可以有多个联系人,一个联系人对应一个顾客。

1.配置文件

Customer.java

package cn.qlq.domain;

import java.util.HashSet;
import java.util.Set; public class Customer {
private Long cust_id; private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
//使用set集合,表达一对多关系
private Set<LinkMan> linkMens = new HashSet<LinkMan>();
public Set<LinkMan> getLinkMens() {
return linkMens;
}
public void setLinkMens(Set<LinkMan> linkMens) {
this.linkMens = linkMens;
}
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_linkman() {
return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
} }

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">
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.qlq.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="Customer" table="cst_customer" >
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="cust_id" >
<!-- generator:主键生成策略 -->
<!--identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键. -->
<generator class="native"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="cust_name" column="cust_name" >
<!-- <column name="cust_name" sql-type="varchar" ></column> -->
</property>
<property name="cust_source" column="cust_source" ></property>
<property name="cust_industry" column="cust_industry" ></property>
<property name="cust_level" column="cust_level" ></property>
<property name="cust_linkman" column="cust_linkman" ></property>
<property name="cust_phone" column="cust_phone" ></property>
<property name="cust_mobile" column="cust_mobile" ></property> <!-- 集合,一对多关系,在配置文件中配置 -->
<!--
name属性:集合属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名
-->
<set name="linkMens">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
</class>
</hibernate-mapping>

LinkMan.java

package cn.qlq.domain;

//联系人实体
public class LinkMan {
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_mobile;
private String lkm_memo;
private String lkm_position; // 表达多对一关系
private Customer customer; public Customer getCustomer() {
return customer;
} public void setCustomer(Customer customer) {
this.customer = customer;
} public Long getLkm_id() {
return lkm_id;
} public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
} public Character getLkm_gender() {
return lkm_gender;
} public void setLkm_gender(Character lkm_gender) {
this.lkm_gender = lkm_gender;
} public String getLkm_name() {
return lkm_name;
} public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
} public String getLkm_phone() {
return lkm_phone;
} public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
} public String getLkm_email() {
return lkm_email;
} public void setLkm_email(String lkm_email) {
this.lkm_email = lkm_email;
} public String getLkm_qq() {
return lkm_qq;
} public void setLkm_qq(String lkm_qq) {
this.lkm_qq = lkm_qq;
} public String getLkm_mobile() {
return lkm_mobile;
} public void setLkm_mobile(String lkm_mobile) {
this.lkm_mobile = lkm_mobile;
} public String getLkm_memo() {
return lkm_memo;
} public void setLkm_memo(String lkm_memo) {
this.lkm_memo = lkm_memo;
} public String getLkm_position() {
return lkm_position;
} public void setLkm_position(String lkm_position) {
this.lkm_position = lkm_position;
} }

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 package="cn.qlq.domain" >
<class name="LinkMan" table="cst_linkman" >
<id name="lkm_id" >
<generator class="native"></generator>
</id>
<property name="lkm_gender" ></property>
<property name="lkm_name" ></property>
<property name="lkm_phone" ></property>
<property name="lkm_email" ></property>
<property name="lkm_qq" ></property>
<property name="lkm_mobile" ></property>
<property name="lkm_memo" ></property>
<property name="lkm_position" ></property> <!-- 多对一 -->
<!--
name属性:引用属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer"></many-to-one>
</class>
</hibernate-mapping>

2.测试代码

1.简单的添加一个顾客张三

    /**
* 添加一个顾客张三
*/
@Test
public void fun1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); //------------------S业务逻辑------------
Customer c = new Customer();
c.setCust_name("张三");
c.setCust_industry("金融行业");
c.setCust_phone("18545869586");
//------------------E业务逻辑------------ session.save(c);
tx.commit();
}

SQL:

Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)

2.给张三增加1个联系人

    /**
* 给张三增加1个联系人
*/
@Test
public void fun2(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); //------------------S业务逻辑------------//
Customer c = session.get(Customer.class, 1l);//项目中可能是根据顾客姓名等信息获取到顾客实体(持久态)
LinkMan m1 = new LinkMan();
m1.setLkm_name("后来给张三添加的联系人"); //维护二者的关系,下面两种方式二选一
// c.getLinkMans().add(m1);
m1.setCustomer(c); session.save(m1);//将m1设置为持久态,不用执行session.update((c)是因为c对象本来处于持久态)
//------------------E业务逻辑------------//
tx.commit();
}

SQL:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lk_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)

3.给上面新增加的联系人修改信息

    /**
* 给上面新增加的联系人修改信息
*/
@Test
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); /***------------------S业务逻辑------------**/
LinkMan linkMan = session.get(LinkMan.class, 1l);
linkMan.setLkm_name("修改过的名字");
// session.update(linkMan);//不用执行这句话是因为获取出来的对象本来处于持久态
/***------------------E业务逻辑------------**/ tx.commit();
}

SQL:

Hibernate:
select
linkman0_.lkm_id as lkm_id1_1_0_,
linkman0_.lkm_gender as lkm_gend2_1_0_,
linkman0_.lkm_name as lkm_name3_1_0_,
linkman0_.lkm_phone as lkm_phon4_1_0_,
linkman0_.lkm_email as lkm_emai5_1_0_,
linkman0_.lkm_qq as lkm_qq6_1_0_,
linkman0_.lkm_mobile as lkm_mobi7_1_0_,
linkman0_.lkm_memo as lkm_memo8_1_0_,
linkman0_.lkm_position as lkm_posi9_1_0_,
linkman0_.lk_cust_id as lk_cust10_1_0_
from
cst_linkman linkman0_
where
linkman0_.lkm_id=?
Hibernate:
update
cst_linkman
set
lkm_gender=?,
lkm_name=?,
lkm_phone=?,
lkm_email=?,
lkm_qq=?,
lkm_mobile=?,
lkm_memo=?,
lkm_position=?,
lk_cust_id=?
where
lkm_id=?

4.删除一个联系人(分为两种:第一种是简单的去掉二者的外键关系---linkman表外键的值设为null,第二种是彻底从库中删除数据----linkman表数据删除)

    /**
* 删除一个联系人(分为两种:第一种是简单的去掉二者的外键关系,第二种是彻底从库中删除数据)
*/
@Test
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); /***------------------S业务逻辑------------**/
//第一种:去掉二者的关系但是不删除数据
// Customer c = session.get(Customer.class, 1l);//项目中可能是根据顾客姓名等信息获取到顾客实体(持久态)
// LinkMan linkMan = session.get(LinkMan.class, 3l);
// c.getLinkMans().remove(linkMan); //第二种:彻底的删除数据
LinkMan linkMan = session.get(LinkMan.class, 3l);
session.delete(linkMan);
/***------------------E业务逻辑------------**/ tx.commit();
}

5.添加一个顾客,同时添加多个联系人

    /**
* 添加一个顾客,同时添加多个联系人
*/
@Test
public void fun5() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); Customer c = new Customer();
c.setCust_name("李四");
c.setCust_industry("IT行业");
c.setCust_phone("18545869587"); LinkMan m1 = new LinkMan();
LinkMan m2 = new LinkMan();
m1.setLkm_name("联系人1");
m2.setLkm_name("联系人2"); //维护关系
// c.getLinkMans().add(m1);
// c.getLinkMans().add(m2);
m1.setCustomer(c);
m2.setCustomer(c); session.save(c);
session.save(m1);
session.save(m2);
tx.commit();
}

SQL:

Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lk_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lk_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)

6.删除一个顾客,级联删除联系人

    /**
* 删除一个顾客,级联删除联系人
*/
@Test
public void fun6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); /***------------------S业务逻辑------------**/
//第一种:去掉二者的关系但是不删除数据
Customer c = session.get(Customer.class, 2l);//项目中可能是根据顾客姓名等信息获取到顾客实体(get方法获取出来的实体处于持久态)
for(LinkMan man : c.getLinkMans()){
session.delete(man);
} //第二种:彻底的删除数据
session.delete(c);
/***------------------E业务逻辑------------**/ tx.commit();
}

SQL:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
select
linkmans0_.lk_cust_id as lk_cust10_1_0_,
linkmans0_.lkm_id as lkm_id1_1_0_,
linkmans0_.lkm_id as lkm_id1_1_1_,
linkmans0_.lkm_gender as lkm_gend2_1_1_,
linkmans0_.lkm_name as lkm_name3_1_1_,
linkmans0_.lkm_phone as lkm_phon4_1_1_,
linkmans0_.lkm_email as lkm_emai5_1_1_,
linkmans0_.lkm_qq as lkm_qq6_1_1_,
linkmans0_.lkm_mobile as lkm_mobi7_1_1_,
linkmans0_.lkm_memo as lkm_memo8_1_1_,
linkmans0_.lkm_position as lkm_posi9_1_1_,
linkmans0_.lk_cust_id as lk_cust10_1_1_
from
cst_linkman linkmans0_
where
linkmans0_.lk_cust_id=?
Hibernate:
update
cst_linkman
set
lk_cust_id=null
where
lk_cust_id=?
Hibernate:
delete
from
cst_linkman
where
lkm_id=?
Hibernate:
delete
from
cst_linkman
where
lkm_id=?
Hibernate:
delete
from
cst_customer
where
cust_id=?

3.进阶操作

1.级联操作   配置级联更新、保存和级联删除(开发中设置级联保存和更新即可,一般是业务中手动删除)-----------当前对象中有变动的另一方的时候会级联更新另一方

         <!--
cascade:级联操作 简化操作.目的就是为了少些两行代码.
值为save-update表示级联保存、更新
值为delete表示级联删除
值为all:save-update+delete
-->
<set name="linkMens" cascade="all">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

1.测试级联更新和保存:

修改Customer.hbm.xml配置:

         <!--
cascade:级联操作 简化操作.目的就是为了少些两行代码.
值为save-update表示级联保存、更新
值为delete表示级联删除
值为all:save-update+delete
-->
<set name="linkMens" cascade="save-update">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

测试代码

    @Test
//保存客户 以及客户 下的联系人
//cascade:save-update
public void fun1(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
Customer c = new Customer();
c.setCust_name("ZDSOft"); LinkMan lm1 = new LinkMan();
lm1.setLkm_name("田七"); LinkMan lm2 = new LinkMan();
lm2.setLkm_name("王八"); //表达一对多,客户下有多个联系人
c.getLinkMens().add(lm1);
c.getLinkMens().add(lm2); //表达对对对,联系人属于哪个客户
lm1.setCustomer(c);
lm2.setCustomer(c); session.save(c);
//级联操作相比于原来少了下面两行代码
// session.save(lm1);
// session.save(lm2); //-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
} @Test
//级联更新
//cascade:save-update
public void fun2(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
Customer c = session.get(Customer.class, 1l); LinkMan lm1 = new LinkMan();
lm1.setLkm_name("大9"); c.getLinkMens().add(lm1);
session.update(c);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}

2.测试级联删除

直接删除的时候会将外键置为null,不会删除数据库数据,查看SQL和数据库结果:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
update
cst_linkman
set
lkm_cust_id=null
where
lkm_cust_id=?
Hibernate:
delete
from
cst_customer
where
cust_id=?

将级联删除设置上之后查看SQL和数据库结果:

         <!--
cascade:级联操作 简化操作.目的就是为了少些两行代码.
值为save-update表示级联保存、更新
值为delete表示级联删除
值为all:save-update+delete
-->
<set name="linkMens" cascade="delete">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

SQL:

Hibernate:
select
customer0_.cust_id as cust_id1_0_0_,
customer0_.cust_name as cust_nam2_0_0_,
customer0_.cust_source as cust_sou3_0_0_,
customer0_.cust_industry as cust_ind4_0_0_,
customer0_.cust_level as cust_lev5_0_0_,
customer0_.cust_linkman as cust_lin6_0_0_,
customer0_.cust_phone as cust_pho7_0_0_,
customer0_.cust_mobile as cust_mob8_0_0_
from
cst_customer customer0_
where
customer0_.cust_id=?
Hibernate:
select
linkmens0_.lkm_cust_id as lkm_cus10_1_0_,
linkmens0_.lkm_id as lkm_id1_1_0_,
linkmens0_.lkm_id as lkm_id1_1_1_,
linkmens0_.lkm_gender as lkm_gend2_1_1_,
linkmens0_.lkm_name as lkm_name3_1_1_,
linkmens0_.lkm_phone as lkm_phon4_1_1_,
linkmens0_.lkm_email as lkm_emai5_1_1_,
linkmens0_.lkm_qq as lkm_qq6_1_1_,
linkmens0_.lkm_mobile as lkm_mobi7_1_1_,
linkmens0_.lkm_memo as lkm_memo8_1_1_,
linkmens0_.lkm_position as lkm_posi9_1_1_,
linkmens0_.lkm_cust_id as lkm_cus10_1_1_
from
cst_linkman linkmens0_
where
linkmens0_.lkm_cust_id=?
Hibernate:
update
cst_linkman
set
lkm_cust_id=null
where
lkm_cust_id=?
Hibernate:
delete
from
cst_linkman
where
lkm_id=?
Hibernate:
delete
from
cst_linkman
where
lkm_id=?
Hibernate:
delete
from
cst_customer
where
cust_id=?

结果数据库数据也被删掉。

2.关系维护  inverse属性配置谁维护关系 (维护外键的值)

在保存时.两方都会维护外键关系.关系维护两次,冗余了. 多余的维护关系语句,显然是客户这一端在维护关系

比如我们级联保存的时候是在一的一方先插入两条数据,然后在修改一的一方的外键为多的一方的主键,查看SQL:

测试代码:

    @Test
//保存客户 以及客户 下的联系人
//cascade:save-update
public void fun1(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
Customer c = new Customer();
c.setCust_name("ZDSOft"); LinkMan lm1 = new LinkMan();
lm1.setLkm_name("田七"); LinkMan lm2 = new LinkMan();
lm2.setLkm_name("王八"); //表达一对多,客户下有多个联系人
c.getLinkMens().add(lm1);
c.getLinkMens().add(lm2); //表达对对对,联系人属于哪个客户
lm1.setCustomer(c);
lm2.setCustomer(c); session.save(c);
//级联操作相比于原来少了下面两行代码
// session.save(lm1);
// session.save(lm2); //-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}

SQL

Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lkm_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?

解决上述的办法:Customer不维护关系,只交给LinkMan进行管理,修改Customer.hbm.xml:

         <!--
cascade:级联操作 简化操作.目的就是为了少些两行代码.
值为save-update表示级联保存、更新
值为delete表示级联删除
值为all:save-update+delete
-->
<!-- inverse属性: 配置关系是否维护.
true: customer不维护关系
false(默认值): customer维护关系 inverse属性: 性能优化.提高关系维护的性能.
原则: 无论怎么放弃,总有一方必须要维护关系.
一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
-->
<set name="linkMens" inverse="true" cascade="all">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

测试代码:

    /**
* 添加一个顾客,同时添加多个联系人
*/
@Test
public void fun5() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction(); Customer c = new Customer();
c.setCust_name("李四");
c.setCust_industry("IT行业");
c.setCust_phone("18545869587"); LinkMan m1 = new LinkMan();
LinkMan m2 = new LinkMan();
m1.setLkm_name("联系人1");
m2.setLkm_name("联系人2"); //维护关系
// c.getLinkMans().add(m1);
// c.getLinkMans().add(m2);
m1.setCustomer(c);
m2.setCustomer(c); session.save(c);
session.save(m1);
session.save(m2);
tx.commit();
}

SQL: (插入的时候就会插入外键的值,因为它知道所属的外键值)

Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lk_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
cst_linkman
(lkm_gender, lkm_name, lkm_phone, lkm_email, lkm_qq, lkm_mobile, lkm_memo, lkm_position, lk_cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?, ?)

测试删除:

    @Test
//删除客户(如果不维护关系的话需要设置级联的才可以删除,也可以维护关系会将相关外键置为null)
public void fun2(){
//1 获得session
Session session = HibernateUtil.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-------------------------------------------------
//3操作
Customer customer = session.get(Customer.class, 5l); session.delete(customer);
//-------------------------------------------------
//4提交事务
tx.commit();
//5关闭资源
session.close();
}

  注意:如果不维护关系也未设置级联删除直接删除会报错,有外键引用。

  解决办法:

    第一种:自己维护关系但是不级联删除,会在删除的时候将相关子表的外键置为null

        <set name="linkMens">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

  第二种:自己不维护关系但是级联删除,会在删除的时候也删除子表的数据。

        <set name="linkMens" inverse="true" cascade="all">
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>

总结:

    O 对象            一的一方使用集合. 多的一方直接引用一的一方.
R 关系型数据库 多的一方使用外键引用一的一方主键.
M 映射文件 一: <set name="">
<key column="" />
<one-to-many class="" />
</set>
多: <many-to-one name="" column="" class="" /> 操作: 操作管理级别属性. cascade: 级联操作
减少我们书写的操作代码.
none(默认值) 不级联
save-update: 级联保存
delete: 级联删除
all: 级联保存+级联删除
结论: 可以使用save-update.不推荐使用delete. 也可以不用cascade.
inverse: 反转关系维护
属于性能优化.关系的两端如果都书写了关系.那么两方都会发送维护关系的语句.
这样,语句就发生重复.我们可以使用inverse使一的一方放弃维护关系.
true 放弃
false(默认值) 维护
结论: 在一对多中,一的一方可以放弃维护关系.

自己的总结:

1.首先需要理解所以状态的更新都是在持久态状态的基础上进行的,get()\update()\save都是为了让对象变为持久态。

2.维护关系的时候一般是多的一方维护关系,少的一方放弃维护关系。比如联系人维护关系,顾客放弃维护关系。。。。。

3.如果设置了级联保存和更新会对其内置属性起作用,为的是少写两行代码。

4.设置级联更新是为了报错顾客的时候也保存联系人,为了省去保存联系人的代码:(前提是其维护关系)----级联操作的意思是如果当前顾客联系人中有变动会级联去更新联系人信息,但是不会去-----外建的维护关系是谁维护外键的值。

(1)xml中配置他维护关系

如果维护关系,代码写成下面这样会级联保存

如果代码写成下面这样,即使设置级联更新也不会保存联系人,如下:

 (2)xml中设置他不维护关系,如下面配置:

代码写成下面这样,即使维护了一对多的关系,但是它不维护外键关系,因为联系人不知道其所属的顾客,所以虽然保存了联系人但是查到联系人的数据外键为null:

如果代码写成下面这样,会级联保存,而且联系人的表中也会生成外键信息,因为联系人维护外键关系,而且联系人也知道其所属的顾客。

  也就是级联操作是当前对象的另一方如果有变动会级联更新另一方(只是简单的插入和修改,不管外键关系),维护关系的意思是谁维护外键关系谁负责修改其所属关系,前提是它知道外键的值。

hibernate的一对多和多对一关联的更多相关文章

  1. Hibernate一对多、多对一关联

    一对多.多对一关联:在多方加外键 示例:Group(一方)和User(多方),一个Group可以有多个User,每个User只能属于一个Group   多对一单向关联 在User(多方)中建Group ...

  2. Hibernate中一对多和多对一关系

    1.单向多对一和双向多对一的区别? 只需要从一方获取另一方的数据时 就使用单向关联双方都需要获取对方数据时 就使用双向关系 部门--人员 使用人员时如果只需要获取对应部门信息(user.getdept ...

  3. Mybatis 一对一、一对多、多对多关联之级联添加

    示例项目:MIPO_CRM 一.一对一关联 示例:订单与销售机会 描述:在业务员与客户的联系人的联系记录中可以生成一条销售机会,而此条销售机会可生成一条订单,两者呈一对一关联. 1.表设计 oppor ...

  4. hibernate 2 一对多、多对一 双向映射

    多对一或一对多中,在多的一方维护关系效率高 一:java实体类 1.Classes.java package cn.gs.ly.school.entity; import java.util.Set; ...

  5. Hibernate自身一对多和多对多关系映射

    一对多关系映射大家都明白,关系双方都一个含有对方多个引用,但自身一对多很多同学都不明白什么意思,那么首先我就说明一下什么是自身一对多,其实也很好理解,自身一对多就是自身含有本身的多个引用,例如新闻类别 ...

  6. MyBatis-Plus不写任何resultMap和SQL执行一对一、一对多、多对多关联查询

    对于一对一,一对多的关联查询,Mybatis-Plus官方示例(mybatis-plus-sample-resultmap)在处理时,需要编写查询方法及配置resultMap,并且写SQL. 为了简化 ...

  7. mybatis实现多表一对一,一对多,多对多关联查询

    原文:https://blog.csdn.net/m0_37787069/article/details/79247321 1.一对一关键字:association作用:针对pojo对象属性的映射  ...

  8. java框架之Hibernate(3)-一对多和多对多关系操作

    一对多 例:一个班级可以有多个学生,而一个学生只能属于一个班级. 模型 package com.zze.bean; import java.util.HashSet; import java.util ...

  9. Hibernate 中一对多和多对多映射

    1. 一对多映射 1.1 JavaWeb 一对多建表原则 多方表的外键指向一方表的主键; 1.2 编写一对多的 JavaBean // 客户(一方)和联系人(多方) // 客户(一方) JavaBea ...

随机推荐

  1. Alpha 冲刺八

    团队成员 051601135 岳冠宇 051604103 陈思孝 031602629 刘意晗 031602248 郑智文 031602234 王淇 会议照片 项目燃尽图 项目进展 完善各自部分 项目描 ...

  2. poi中如何自定义日期格式

    1. poi的“Quick Guide”中提供了 “How to create date cells ”例子来说明如何创建日期单元格,代码如下: HSSFCellStyle cellStyle = w ...

  3. WORDPRESS修改文章文件后,出现乱码

    文章文件(single.php)发生改变时,部分静态文字出现乱码 解决方案: 1.进入你的ftp空间,进入你的主题文件夹,选取你要加中文文字的那个文件,例如我的就是footer.php. 2.把foo ...

  4. 模拟事件【JavaScript高级程序设计第三版】

    事件,就是网页中某个特别值得关注的瞬间.事件经常由用户操作或通过其他浏览器功能来触发.但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样 ...

  5. sql bak还原到新数据库

    1 创建新数据库  TestDB 2  使用语句 use master restore database [TestDB] from disk = 'D:\SqlDataBak\SanJu\SanJu ...

  6. Degree Set CodeForces - 976D(双指针)

    题意: 构造一个无向图,使得无向图里的所有点的度数 所组成的集合 即为给出的几个数 解析: 题中的数是以上升的顺序给出的, 我们对于dn+1个数进行处理,对于当前数i,有两个操作 1.向后边的所有点连 ...

  7. c# 新建文本文件、遍历读取文本、删除文本行

    如果该物理路径没有该文本则创建一个新文本 if (!File.Exists(@"C:\db.txt")){FileStream fs = new FileStream(@" ...

  8. C语言常用修饰符

    前言 这两天在梳理自己C语言的知识,发现写了这么久的代码,居然所有的知识点都在自己的脑袋里.这可不好,万一老了呢.... 接下来的几天里,会以文字的形式,将这些知识整理出来,分享给大家. 想要看看英文 ...

  9. 【转】PCB中3D相关功能详解

    如果PCB Layout工程师能够在设计过程中,使用设计工具直观地看到自己设计板子的实际情况,将能够有效的帮助他们的工作.尤其现在PCB板的设计越来越复杂,密度越来越高,如果能够洞察多层板内部则可以帮 ...

  10. 洛谷 P4112 [HEOI2015]最短不公共子串 解题报告

    P4112 [HEOI2015]最短不公共子串 题目描述 在虐各种最长公共子串.子序列的题虐的不耐烦了之后,你决定反其道而行之. 一个串的"子串"指的是它的连续的一段,例如bcd是 ...