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:

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

(二:级联删除)

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

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

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

 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执行过程

(一对多修改操作)

执行结果底层的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,就是放弃外键维护

底层SQL的变化:

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. [MySQL数据库之表的约束条件:primary key、auto_increment、not null与default、unique、foreign key:表与表之间建立关联]

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

  5. 【CoreData】表之间的关联

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

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

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

  7. Hibernate_day03--课程安排_表之间关系_一对多操作

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

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

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

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

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

随机推荐

  1. Unicode解码转换为中文

    Unicode转中文2:Regex.Unescape(string str);str格式:"\uxxxx" ,举例:"\u300d"

  2. TinyXML中类分析

    TiXmlElement: 对应于XML的元素,定义了对element的相关操作 成员函数: TiXmlElement (const char * in_value); TiXmlElement( c ...

  3. WTF

    WTF ,luna黑色主题比较sublime 还是差点!

  4. ASP.NET MVC判断基于Cookie的Session过期

    当我们第一次请求访问时,可以看到Response的Set-Cookie里添加了ASP.NET_SessionId的值,以后再访问时可以看到Resquest里的Cookie已经包含这个Key.   Se ...

  5. 使用JWT设计SpringBoot项目api接口安全服务

    转载直: 使用JWT设计SpringBoot项目api接口安全服务

  6. De Moivre–Laplace theorem 掷硬币

    De Moivre–Laplace theorem - Wikipedia https://en.wikipedia.org/wiki/De_Moivre%E2%80%93Laplace_theore ...

  7. 图解 servlet 与jsp的关系

    Servlet是Java提供的用于开发Web服务器应用程序的一个组件,运行在服务器端,由Servlet容器所管理,用于生成动态的内容.Servlet是平台独立的Java类,编写一个Servlet,实际 ...

  8. webpack 的编译原理

    自从接触了react,vue 这两个框架,都会用到webpack这个打包工具.面试的时候,经常被问到知道webpack的编译原理吗? 可以简单的介绍一下.每每这个时候都被问的哑口无言,平时用的时候挺顺 ...

  9. Parameter 'username' not found. Available parameters are [1, 0, param1, param2]

    只要把dao层的***Mapper.java代码的参数加上@param 才可以 修改前的代码 public User selectLogin(String username,String passwo ...

  10. Python(1)(安装与基本使用)

    1.Python的下载和安装我就不废话了,百度上都有. 我安装的是Python 3.4.3 64bit 安装完之后,打开Cmd,输入Python 显示以上相同,按照百度的意思就是安装成功. 2.配置环 ...