Hibernate中表与表之间的关联一对多,级联保存和级联删除

时间:2023-02-04 08:49:11

Hibernate中表与表之间的关联一对多,级联保存和级联删除Hibernate中表与表之间的关联一对多,级联保存和级联删除Hibernate中表与表之间的关联一对多,级联保存和级联删除Hibernate中表与表之间的关联一对多,级联保存和级联删除

1:Hibernate的一对多操作(重点)

  一对多映射配置

  第一步:创建两个实体类:客户和联系人(例)以客户为一,联系人为多:  

 package com.yinfu.entity;

 public class LinkMan {

     private Integer lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
public Integer getLkm_id() {
return lkm_id;
}
public void setLkm_id(Integer lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
}

LinkMan

 package com.yinfu.entity;

 public class Customer {

     private Integer cid;
private String custName;
private String custLevel;
private String custSource;
private String custPhone;
private String custMobile;
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;
}
}

Customer

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

    在客户实体类里面表示多个联系人(一个客户里面多个联系人):

 package com.yinfu.entity;

 import java.util.HashSet;
import java.util.Set; public class Customer { private Integer cid;
private String custName;
private String custLevel;
private String custSource;
private String custPhone;
private String custMobile; //客户中表示多个联系人,一个客户有多个联系人
//Hibernate要求使用集合表示多的数据,有set表示(set无序,主要是set可有重复元素)
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 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;
}
}

Customer

    联系人实体类里面表示所属客户(一个联系人只能属于一个客户):

 package com.yinfu.entity;

 public class LinkMan {

     private Integer lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone; //在联系人中表示所属客户,一个联系人对应一个客户
private Customer customer; public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getLkm_id() {
return lkm_id;
}
public void setLkm_id(Integer lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
}

LinkMan

  第三步:配置映射关系(映射文件)

    在映射文件中配置一对多关系

    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="com.yinfu.entity.Customer" table="t_customer">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="custName" column="custName"></property>
<property name="custLevel" column="custLevel"></property>
<property name="custSource" column="custSource"></property>
<property name="custPhone" column="custPhone"></property>
<property name="custMobile" column="custMobile"></property>
<!-- 客户配置文件中表示所有的联系人
set标签表示所有联系人
set标签中的name属性:写在客户实体类里面表示所有联系人的set集合名称
-->
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
<!-- 一对多建表有外键
Hibernate机制:双向维护外键,在一和多那方都配置外键
column属性:外键值
-->
<key column="clid"></key>
<!-- 客户表表示的所有联系人,class表示联系人实体类的全类名 -->
<one-to-many class="com.yinfu.entity.LinkMan"/>
</set>
</class> </hibernate-mapping>

Customer.hbm.xml

    LinkMan的配置文件:

 <?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.yinfu.entity.LinkMan" table="t_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<!-- 表示联系人所属的客户
name属性:在联系人实体类中用来表示客户的字段名
class属性:客户实体类的全类名
column属性:外键名,要与客户映射文件中的外键名相同
-->
<many-to-one name="customer" class="com.yinfu.entity.Customer" column="clid"></many-to-one>
</class> </hibernate-mapping>

LinkMan.hbm.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>
<!-- 此配置文件的文件名和位置是固定的的
文件名:hibernate.cfg.xml
位置:要写在src文件中
-->
<session-factory>
<!-- 第一部分:配置数据库信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">song12345</property> <!-- 第二部分:配置hibernate信息(可有可无) -->
<!-- 输出底层的SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 对底曾语句进行格式化 -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate帮创建表,需要配置
update:如果有表就更新,没有表就创建
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置数据库的方言
识别不同数据库中的特有的语句和关键字
比如:分页查询
MySQL关键字是limit
oracle中的使用的是top-n分析中的rownum
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 指定线程管理方式,与本地线程进行绑定,实现单线程操作 -->
<property name="hibernate.current_session_context_class">thread</property> <!-- 第三部分:把映射文件放到核心配置文件中 -->
<mapping resource="com/yinfu/entity/Customer.hbm.xml"/>
<mapping resource="com/yinfu/entity/LinkMan.hbm.xml"/>
</session-factory> </hibernate-configuration>

hibernate.cfg.xml

  创建工具类生成SessionFactory和session对象

 package com.yinfu.utils;

 import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration; //工具类
public class HibernateUtils { private final static Configuration cfg;
private final static SessionFactory sessionFactory; //用静态代码块来实现对象只在类加载的时候创建一次(静态代码块只执行一次)
static{
//创建configuration对象,
cfg = new Configuration();
cfg.configure();
//根据Configuration对象创建sessionFactory对象
sessionFactory = cfg.buildSessionFactory();
} //返回与本地线程绑定的session
public static Session getSession(){
return sessionFactory.getCurrentSession();
} //创建一个方法用于返回sessionFactory对象
public static SessionFactory getSessionFactory(){
return sessionFactory;
} }

HibernateUtils

在工具类中直接写一个main方法,内部不写代码,直接执行,生成两个表,而外键是在一对多的多中的表上创建的

(一:级联保存):

复杂的测试类:

 package com.yinfu.test;

 import java.util.List;

 import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test; import com.yinfu.entity.Customer;
import com.yinfu.entity.LinkMan;
import com.yinfu.entity.User;
import com.yinfu.utils.HibernateUtils; public class HibernateOneToMany { //一对多的级联保存
@Test
public void testAddDemo(){
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction(); //添加客户,为这个客户添加一个联系人
//1:创建客户和联系人对象
Customer customer = new Customer();
customer.setCustName("传智播客");
customer.setCustLevel("VIP");
customer.setCustSource("网络");
customer.setCustMobile("110");
customer.setCustPhone("911"); LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("张三");
linkMan.setLkm_gender("男");
linkMan.setLkm_phone("123");; //2:客户里面表示所有联系人,联系人里面表示客户
//建立客户对象和联系人对象关系
//2.1:把联系人对象放到客户对象中的set集合里面
customer.getSetLinkMan().add(linkMan);
//2.2把客户对象放到联系人中的Customer属性中
linkMan.setCustomer(customer); //3:保存到数据库
session.save(customer);
session.save(linkMan); tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
}finally{
session.close();
sessionFactory.close();
}
}
}

HibernateOneToMany

简化做法:

首先在Customer的配置文件Customer.hbm.xml文件中的set标签上添加一个cascade属性值为save-update:Hibernate中表与表之间的关联一对多,级联保存和级联删除

然后在测试类中这样修改一下就行:

Hibernate中表与表之间的关联一对多,级联保存和级联删除

(二:级联删除)

删除客户的同时将客户对应的联系人全部删除

首先在Customer的配置文件Customer.hbm.xml文件中的set标签上添加一个cascade属性值为delete,如果cascade属性有多个值,用英文逗号隔开;

Hibernate中表与表之间的关联一对多,级联保存和级联删除

测试代码:根据ID查出customer在调用delete方法就行:

Hibernate中表与表之间的关联一对多,级联保存和级联删除

 Hibernate:
select
customer0_.cid as cid1_0_0_,
customer0_.custName as custName2_0_0_,
customer0_.custLevel as custLeve3_0_0_,
customer0_.custSource as custSour4_0_0_,
customer0_.custPhone as custPhon5_0_0_,
customer0_.custMobile as custMobi6_0_0_
from
t_customer customer0_
where
customer0_.cid=?
Hibernate:
select
setlinkman0_.clid as clid5_1_0_,
setlinkman0_.lkm_id as lkm_id1_1_0_,
setlinkman0_.lkm_id as lkm_id1_1_1_,
setlinkman0_.lkm_name as lkm_name2_1_1_,
setlinkman0_.lkm_gender as lkm_gend3_1_1_,
setlinkman0_.lkm_phone as lkm_phon4_1_1_,
setlinkman0_.clid as clid5_1_1_
from
t_linkman setlinkman0_
where
setlinkman0_.clid=?
Hibernate:
update
t_linkman
set
clid=null
where
clid=?
Hibernate:
delete
from
t_linkman
where
lkm_id=?
Hibernate:
delete
from
t_customer
where
cid=?

内部SQL执行过程

(一对多修改操作)

Hibernate中表与表之间的关联一对多,级联保存和级联删除

执行结果底层的SQL语句:(这样存在双向维护外键,存在性能不足)

 Hibernate:
select
customer0_.cid as cid1_0_0_,
customer0_.custName as custName2_0_0_,
customer0_.custLevel as custLeve3_0_0_,
customer0_.custSource as custSour4_0_0_,
customer0_.custPhone as custPhon5_0_0_,
customer0_.custMobile as custMobi6_0_0_
from
t_customer customer0_
where
customer0_.cid=?
Hibernate:
select
linkman0_.lkm_id as lkm_id1_1_0_,
linkman0_.lkm_name as lkm_name2_1_0_,
linkman0_.lkm_gender as lkm_gend3_1_0_,
linkman0_.lkm_phone as lkm_phon4_1_0_,
linkman0_.clid as clid5_1_0_
from
t_linkman linkman0_
where
linkman0_.lkm_id=?
Hibernate:
select
setlinkman0_.clid as clid5_1_0_,
setlinkman0_.lkm_id as lkm_id1_1_0_,
setlinkman0_.lkm_id as lkm_id1_1_1_,
setlinkman0_.lkm_name as lkm_name2_1_1_,
setlinkman0_.lkm_gender as lkm_gend3_1_1_,
setlinkman0_.lkm_phone as lkm_phon4_1_1_,
setlinkman0_.clid as clid5_1_1_
from
t_linkman setlinkman0_
where
setlinkman0_.clid=?
Hibernate:
下面进行了两次修改,由于Hibernate是双向维护外键,所以,客户和联系人中都要进行外键维护,存在性能不足
update
t_linkman
set
lkm_name=?,
lkm_gender=?,
lkm_phone=?,
clid=?
where
lkm_id=?
Hibernate:
update
t_linkman
set
clid=?
where
lkm_id=?

底层SQL语句

性能优化,解决方法,在一对多中让一放弃外键维护,即让customer放弃外键维护

具体实现:

在需要放弃外键的对象的映射文件中的set标签中进行配置,添加inverse属性:默认值是false,修改为true,就是放弃外键维护

Hibernate中表与表之间的关联一对多,级联保存和级联删除

底层SQL的变化:

Hibernate中表与表之间的关联一对多,级联保存和级联删除

Hibernate中表与表之间的关联一对多,级联保存和级联删除的更多相关文章

  1. Hibernate中表与表之间的关联多对多,级联保存,级联删除

    第一步:创建两个实体类:用户和角色实体类,多对多关系,并让两个实体类之间互相关联: 用户实体类: package com.yinfu.entity; import java.util.HashSet; ...

  2. mybatis中表与表之间的关联

    第三天 1.mybatis处理表与表之间的关系? 比如要在帖子回复表里显示其它两张相关联表的信息. 处理的第一种方式: 1)主要的数据实体类是ReplyInfo,相关联的实体表的数据是TitleInf ...

  3. mysql 中表与表之间的关系

    如何找出两张表的对应关系 分析步骤: 1.先找出左表的角度去找 ​ 是否左表的多条记录可以对应右表的一条记录,如果是,则证明左表的一个字段foreign key 右表一个字段 (通常是id) 2.再站 ...

  4. &lbrack;MySQL数据库之表的约束条件:primary key、auto&lowbar;increment、not null与default、unique、foreign key:表与表之间建立关联&rsqb;

    [MySQL数据库之表的约束条件:primary key.auto_increment.not null与default.unique.foreign key:表与表之间建立关联] 表的约束条件 约束 ...

  5. 【CoreData】表之间的关联

    这次是表之间怎么进行关联,要求如下: // 建立学生与班级表之间的联系 既然是表与表之间的关联,那肯定是要先创建表: // 1.创建模型文件 (相当于一个数据库里的表) // New File ——— ...

  6. PowerDesigner如何设计表之间的关联

    PowerDesigner如何设计表之间的关联   步骤/方法 在工具箱中找到参照关系工具:   由地区表到省份表之间拉参照关系,箭头指向父表,然后双击参照关系线,打开参照关系的属性:   在这里检查 ...

  7. Hibernate&lowbar;day03--课程安排&lowbar;表之间关系&lowbar;一对多操作

    Hibernate_day03 上节内容 今天内容 表与表之间关系回顾(重点) Hibernate的一对多操作(重点) 一对多映射配置(重点) 一对多级联操作 一对多级联保存 一对多级联删除 一对多修 ...

  8. (原创)Hibernate 使用过程中(尤其是多对多关联中的级联保存和级联删除)的注意事项(基于项目的总结)

    一.先上知识点: 1.hibernate多对多关联关系中最重要的参数是(基于配置文件xxx.hbm.xml文件形式): 1):inverse属性,如果设置inverse=“true”就代表让对方参与维 ...

  9. Hibernate的级联保存、级联删除

    级联操作: 属性:cascade 值:save-update(级联保存) delete(级联删除) all(级联保存+级联删除) 优点:虽然,不用级联操作也能解决问题.但是级联操作可以减少代码量,使得 ...

随机推荐

  1. zhuang 定制iOS 7中的导航栏和状态栏

    近期,跟大多数开发者一样,我也正忙于对程序进行升级以适配iOS 7.最新的iOS 7外观上有大量的改动.从开发者的角度来看,导航栏和状态栏就发生了明显的变化.状态栏现在是半透明的了,这也就意味着导航栏 ...

  2. sql常识-IN 操作符

    IN 操作符 IN 操作符允许我们在 WHERE 子句中规定多个值. SQL IN 语法 SELECT column_name(s) FROM table_name WHERE column_name ...

  3. 转载:STM32之中断与事件---中断与事件的区别

    这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚 ...

  4. uva 10020 Minimal coverage

    http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&p ...

  5. &lt&semi;php&gt&semi;PDO链接方法

    <?php //定义数据源 $dsn = "mysql:dbname=mydb;host=localhost"; //$dsn = "sqlsrv:dbname=m ...

  6. MyBatis 源码分析——映射结果

    MyBatis最后一步一定是处理相关的结果——把数据映射成对应的模型对象.事实上在笔者看来如果读者们了解了mybatis如何去执行数据库,又是如何处理数据结果.那么就了解了mybatis的主要路线.因 ...

  7. 用VSCode开发一个asp&period;net core2&period;0&plus;angular5项目&lpar;5&rpar;&colon; Angular5&plus;asp&period;net core 2&period;0 web api文件上传

    第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三 ...

  8. 前端开发之基础知识-HTML(二)

    1.6 html链接 html链接 <a>标签可以在网页上定义一个链接地址,通过src属性定义跳转的地址,通过title属性定义鼠标悬停时弹出的提示文字框. <a href=&quo ...

  9. 【转】QPainter中坐标系变换问题

    转自:http://blog.sina.com.cn/s/blog_67cf08270100ww0p.html 一.坐标系简介. Qt中每一个窗口都有一个坐标系,默认的,窗口左上角为坐标原点,然后水平 ...

  10. 解决git冲突造成的Please move or remove them before you can merge

    git clean -d -fx “” 其中x —–删除忽略文件已经对git来说不识别的文件d —–删除未被添加到git的路径中的文件f —–强制运行如果你确定这货已经没用了,并且git status ...