01搭建hibernate框架

02多表关联关系映射

03hibernate各种查询方式


目录

一、搭建环境

二、javabean和xml的基础配置

三、测试多表之间的关联配置效果

一对多级联保存:

TestSave.java

一对多级联删除:

TestDelete.java

拓展了解:

项目文件下载


一、搭建环境

具体参考上篇   (写在前面,hibernate工具类有更新 改成getCurrentSession,核心配置文件里得加一行配置,绑定开启绑定本地session,使用时不需要手动关闭,线程结束自动关闭 不过学校上课说是上ssh,最重要的spring却没教。。因此不存在service层和dao层session的传递,用上篇的getSession也完全可以,想练练ssh整合的就改过来,反正都是死代码,直接当模板用,直接复制粘贴就行了)

本篇的数据库与javabean和上篇不同

两张表:
customer.sql 客户表

create table customer (custId bigint(32) not null auto_increment comment '客户编号(主键)',custName varchar(32) not null comment '客户名称(公司名称)',-- cust_linkman varchar(64) default null comment '联系人(一个客户多个联系人,此处对应map 实际多个选项 不知道填啥)',custPhone varchar(64) default null comment '固定电话',primary key (custId)
) engine=innodb auto_increment=1 default charset=utf8;

linkman.sql   联系人表

create table linkman (lkmId bigint(32) not null auto_increment comment '联系人编号(主键)',lkmName varchar(16) default null comment '联系人姓名',custId bigint(32) not null comment '所代表的客户id',lkmPhone varchar(16) default null comment '联系人办公电话',primary key (lkmId),-- key fk_linkman_customer_id (custid),constraint fk_linkman_customer_id foreign key (custId) references customer (custId) on delete no action on update no action
) engine=innodb auto_increment=3 default charset=utf8;

关系描述:客户与联系人关系:
                   一对多(客户一方  联系人多方)
                   一个客户对应多个联系人,一个联系人对应一个客户。
                  也即你是客户,可以通过你的兄弟,朋友,父母的多个联系人联系到你。但通过你的父母只能联系到你这个客户

表:
     多方表里写一方的主键作为外键,匹配到多方唯一的一方。即:
     联系人表里写客户表的主键作为外键,匹配到联系人对应的唯一的客户

javabean:
     多方javabean(表对应的类对象),写一个一方的类对象对应外键
     一方类对象写一个set集合,存储对应的所有的多方对象
即:
     Linkman类有一个字段属性为"Customer customer;",对应表的外键(而不是和其他属性一下写个简单的字段)
     Customer类有一个属性为"Set<Linkman> linkmans",存储客户所有的中介联系人,表中可以没有对应的列

详细下面有

配好后目录如下:

二、javabean和xml的基础配置

Customer.java

package cn.ahpu.domain;import java.util.HashSet;
import java.util.Set;public class Customer {private Long custId;//客户idprivate String custName;//客户姓名private String custPhone;//客户电话//一对多,一方写集合    具体含义,一个客户有多个联系人  eg:你是客户,公司可以通过你的老师,同学,父母等好多人联系到你//hibernate默认使用set集合 和配置文件对应   数据库表里可以没有此属性对应的列private Set<Linkman> linkmans=new HashSet<Linkman>();//★ 千万注意必须手动初始化  hibernate不会帮你new//省略get/set  自己生成}

Linkman.java

package cn.ahpu.domain;public class Linkman {private Long lkmId;private String lkmName;private String lkmPhone;//一对多 多方写类对象  具体含义 每个联系人只能对应一个客户  eg:通过你的父母只能找到你,不能联系到别人家的孩子private Customer customer;//外键-----一方类写类对象     简单属性,数据库也有对应的匹配列,因而不用自己new         //省略get/set  自己生成}

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><class name="cn.ahpu.domain.Customer" table="customer"><!-- java主键属性与表的主键列名对应   native表示主键自动递增重要总结: 主键为short,int,long用 native主键char,varchar类型 即随机字符串用:uuid--><id name="custId" column="custId"><generator class="native"/></id><!-- 其他非主键属性对应的配置   name为类属性名  column为表列名--><property name="custName" column="custName"/><property name="custPhone" column="custPhone"/><!-- javabean里多写了个set集合 也要专门配置 标签名就叫set 好记--><set name="linkmans"><key column="custId"/><one-to-many class="cn.ahpu.domain.Linkman"/></set><!-- 属性name: 集合名称(还是那个特殊属性的字段名)column: 还是多表的外键名称class: 一方当然也需要多方类的全路径  才能帮你封装所有的联系人类及其数据到我的集合里呀小结:一方多方对于集合或是类对象这个特殊属性的配置本质上都只提供了3个信息,name,column,class就是一方标签配法麻烦点,3个标签(每个分别一个属性)有嵌套关系,多方一个标签3个属性即可--></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="cn.ahpu.domain.Linkman" table="linkman"><!-- java主键属性与表的主键列名对应   native表示主键自动递增重要总结: 主键为short,int,long用 native主键char,varchar类型 即随机字符串用:uuid--><id name="lkmId" column="lkmId"><generator class="native"/></id><!-- 其他非主键属性对应的配置   name为类属性名  column为表列名--><property name="lkmName" column="lkmName"/><property name="lkmPhone" column="lkmPhone"/><!-- 外键的配置 多方就是"多对一" 正好记忆标签的名字--><many-to-one name="customer" class="cn.ahpu.domain.Customer" column="custId"/><!-- <many-to-one name="" class="" column=""/>name: 关联一方类对象的那个属性名  class: 属性类类型的全路径(给了全路径才能帮你new呀 也因此javabean里不用自己new)column: 表中外键列名小结:一方多方对于集合或是类对象这个特殊属性的配置本质上都只提供了3个信息,name,column,class--></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><property name="hibernate.connection.url">jdbc:mysql:///hibernate02</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">root</property><!-- mysql数据库方言 --><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 开启绑定本地session 否则工具类的getCurrentSession那个api用不了--><property name="hibernate.current_session_context_class">thread</property><!-- 打印sql语句以及自动更新表 --><property name="hibernate.show_sql">true</property><property name="hibernate.format_sql">true</property><property name="hibernate.hbm2ddl.auto">update</property><!-- 映射配置文件,需要引入映射的配置文件 --><mapping resource="cn/ahpu/domain/Customer.hbm.xml"/><mapping resource="cn/ahpu/domain/Linkman.hbm.xml"/></session-factory>
</hibernate-configuration>

三、测试多表之间的关联配置效果

一对多级联保存:

其中相对于上面最原始的配置情况:
    run2           不用修改任何配置文件
    run2           Customer.hbm.xml中多配置:     <set ... cascade="save-update">  
                      也即是:一方配置级联
    run2_1       仅linkman.hbm.xml中多配置:<many-to-one ... cascade="save-update"/>
                      也即是:多方配置级联
    run2_2      Customer.hbm.xml中多配置:     <set ... cascade="save-update">  
                      linkman.hbm.xml中多配置:<many-to-one ... cascade="save-update"/>
                     也即是:多方和一方都配置级联 (双向互相级联保存)

注:cascade="save-update" 级联保存方式为:有则更新 没有则保存

每次测试完可以删掉数据库中的两张表,一启动测试(本质是调用getSession这个api)hibernate框架就会根据javabean和配置文件帮你自动创建表结构,自动生成表(hibernate强大到可以让一个没有学过数据库的后端程序员也能轻松地操作操作数据库,当然要是你懒不想学如何写hibernate的xml配置文件,像胡平那样先建好表然后通过eclipse反向工程来反向生成xml配置文件,就无法体会到这种强大了)

TestSave.java

package cn.ahpu.test;import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;import cn.ahpu.domain.Customer;
import cn.ahpu.domain.Linkman;
import cn.ahpu.utils.HibernateUtils;/*** 测试一对多 保存* @author 软件163韩竹安* 2019年12月23日-下午4:36:20*/
public class TestSave {/*** 方法1:最麻烦的双向关联方式,保存数据(就是手动调用get/set方法将对方设置进来)* 优点:不用再动配置文件* 缺点:手动set/get 麻烦*/@Testpublic void run1() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();//添加客户"天河" 他有两个联系人 "天河爸" "天河妈"  也一并添加进来Customer c = new Customer();c.setCustName("天河");Linkman l1 = new Linkman();l1.setLkmName("天河妈");Linkman l2 = new Linkman();l2.setLkmName("天河爸");//双向关联:手动双向添加c.getLinkmans().add(l1);c.getLinkmans().add(l2);l1.setCustomer(c);l2.setCustomer(c);//保存客户session.save(c);session.save(l1);session.save(l2);tr.commit();session.close();}/*** 方法2.0:单向关联,保存数据。就是级联保存 (一方一个个添加多方,多方会自动保存一方)* 优点:一方保存多方即可,不用双向保存* 缺点:多配置一个级联保存* * 当然也可以多方保存一方,然后只保存多方,一方自动保存。级联保存有方向性* 此处保存customer,级联linkman,casecade配置到customer(一方)那边*     <set>配置cascade属性  <set ... cascade="save-update">*/@Testpublic void run2() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();//添加客户"天河" 他有两个联系人 "天河爸" "天河妈"  也一并添加进来Customer c = new Customer();c.setCustName("天河");Linkman l1 = new Linkman();l1.setLkmName("天河妈");Linkman l2 = new Linkman();l2.setLkmName("天河爸");//单向关联:保存其中一边即可c.getLinkmans().add(l1);c.getLinkmans().add(l2);//保存客户  (不需要保存联系人了)session.save(c);tr.commit();}/*** 方法2.1: 单向关联,保存数据。级联保存* 保存linkamn(多方) 级联customer(一方)* * 此处加linkman的配置: <many-to-one ... cascade="save-update"/>   (记得测试前先删掉customer的级联配置)*/@Testpublic void run2_1() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();//添加客户"天河" 他有两个联系人 "天河爸" "天河妈"  也一并添加进来Customer c = new Customer();c.setCustName("天河");Linkman l1 = new Linkman();l1.setLkmName("天河妈");Linkman l2 = new Linkman();l2.setLkmName("天河爸");//单向关联:保存其中一边即可   保存谁 谁主动去添加另一方l1.setCustomer(c);l2.setCustomer(c);//保存联系人   (不需要保存客户了)session.save(l1);//save   此时数据库中没有c1 保存customer表session.save(l2);//update 此时数据库中有c1  更新customer表(此处表太简单,不需要修改啥,但绝对避免了插入两条一样的记录)tr.commit();}/*** 方法2.2: 单向关联,保存数据。级联保存* 双方各保存一次 两边都配置级联* * linkman.hbm.xml和customer.hbm.xml都配置cascade="save-update"  */@Testpublic void run2_2() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();//添加客户"天河" 他有两个联系人 "天河爸" "天河妈"  也一并添加进来Customer c = new Customer();c.setCustName("天河");Linkman l1 = new Linkman();l1.setLkmName("天河妈");Linkman l2 = new Linkman();l2.setLkmName("天河爸");//单向关联:保存其中一边即可   保存谁 谁主动去添加另一方l1.setCustomer(c);//下面保存l1同时保存了c  c.getLinkmans().add(l2);//c已经在数据库中了 操作javabean=操作表  l2也会被保存到表中 因为双方都配置了级联 相互级联session.save(l1);tr.commit();}//小结:方法2.0最好用  也即是:一方配置级联  保存一方 级联多方  (然而保存数据你却不知道是先录入的一方,还是先录入的多方,所以都得掌握)
}

我想,一般情况下,就保存而言,双向都配置级联保存“casecade=“save-update””吧 这样保存任何一方,另一方要是没有的话都会级联保存,新插入没有的记录。所以我就都留着

默认配置更新1:此时默认配置变成更新1,就是双方都加个级联保存,都只多配置一个cascade属性

customer.hbm.xml

linkman.hbm.xml

一对多级联删除:

delete0:        默认配置不变
delete1:        customer.hbm.xml级联里加个属性值delete:<set ... cascade="..,delete">
deleteX:        相对于默认配置更新1: 仅linkman.hbm.xml配置了级联删除: <many-to-one ... cascade="save-update,delete"/>
deleteY:        双方都配置了级联删除,删任何一条数据,哪怕是联系人,相互级联,整个数据库空了

TestDelete.java

package cn.ahpu.test;import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;import cn.ahpu.domain.Customer;
import cn.ahpu.domain.Linkman;
import cn.ahpu.utils.HibernateUtils;/*** 测试一对多 级联删除* @author 软件163韩竹安 * 2019年12月23日-下午6:04:22*/
public class TestDelete {// 导入数据@Testpublic void importDate() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();// 添加客户"天河" 他有两个联系人 "天河爸" "天河妈" 也一并添加进来Customer c = new Customer();c.setCustName("天河");Linkman l1 = new Linkman();l1.setLkmName("天河妈");Linkman l2 = new Linkman();l2.setLkmName("天河爸");// 单向关联:保存其中一边即可c.getLinkmans().add(l1);c.getLinkmans().add(l2);// 保存客户 (不需要保存联系人了)session.save(c);tr.commit();}/*** hibernate正常删除   默认情况:* 删除谁就只删除谁,且一定能删除成功,不会多删除与之有关联的数据,也不会报错说删不了* eg:删除客户,会只删除这个客户,不会删除下面的联系人,也不会报错说你这个客户被某些联系人外键关联了而删不了*      原因:避免外键冲突即可,hibernate会事先将此客户下的所有联系人的外键置为null,再删除就没冲突了(可以通过打印的sql语句察觉到这一点)*/@Testpublic void delete0() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();Customer c = session.get(Customer.class, 1L);session.delete(c);tr.commit();}/*** 删除一方,级联删除旗下所有的多方* eg:一般一方删除了,多方数据没必要保留 eg:删除部门,部门下的员工没有存在的必要的    |  删除客户,不需要联系他了,旗下的联系人也没必要还留在数据库了*     在一方级联配置里加个删除delete*     本来是:        <set name="linkmans" cascade="save-update">*  加个配置改成:   <set name="linkmans" cascade="save-update,delete">   即配置级联删除*  删除客户,级联删除其下的所有联系人*/@Testpublic void delete1() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();Customer c = session.get(Customer.class, 1L);session.delete(c);tr.commit();}/*******************************下面两个配置仅做了解,不需要会,实际开发用不到*****************************//*** 了解,没必要学,一般用不到* 类上面的配置:先删除customer.hbm.xml里的级联删除属性(不删的话待会儿两边都级联删除,两边相互作用可能两张表的数据全没了),*             转而在linkman.hbm.xml里加上级联删除cascade="..,delete"*                此时若删除,联系人,同样会其所属的客户(其他联系人的客户外键变为null)* 了解即可,基本用不到*/@Testpublic void deleteX() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();Linkman l = session.get(Linkman.class, 1L);session.delete(l);tr.commit();}/*** 了解,没必要学,肯定用不到* 两边都配置级联删除,这样删除一个联系人会删除对应客户,而客户也配置了级联,被删除时又去级联删除其下所有的联系人,* 整个联系人客户群体全没了,明显不合理* * 此时双方都配置了级联删除*/@Testpublic void deleteY() {Session session = HibernateUtils.getCurrentSession();Transaction tr = session.beginTransaction();Linkman l = session.get(Linkman.class, 1L);session.delete(l);tr.commit();}
}

一般一方删除,多方也级联删除比较合理,而多方删除一条记录,一方与其他多方不受影响,这样的配置最科学,也即是再加上一方的级联删除配置,多方配置不懂

配置更新2:

customer.hbm.xml:

linkman.hbm.xml:相对于更新1不变

拓展了解:

下面更多的了解下即可(考试肯定不会考,ssh框架在国内也已经过时了,主要学设计思想):

cascade属性的一些常见取值:
    * none                        -- 不使用级联
    * save-update                -- 级联保存或更新
    * delete                    -- 级联删除
    * delete-orphan                -- 孤儿删除.(注意:只能应用在一对多关系)
    * all                        -- 等价于"save-update,delete"
    * all-delete-orphan            -- 等价于"save-update delete delete-orphan"

孤儿删除(孤子删除)(只有在一对多的环境下才有孤儿删除)
    * 在一对多的关系中,可以将一的一方认为是父方.将多的一方认为是子方.孤儿删除:在解除了父子关系的时候.将子方记录就直接删除。(具体表现为在set集合中删除一个子方  本来子方应该只是数据库中的外键字段被置为null了,但孤儿删除报复心态严重,和我解除关系不是简单地外键字段=null,而是把你給弄死(直接从数据库中删了))
    简言之:多方表的外键为null的记录会被hibernate自动给删除
    * <many-to-one cascade="delete-orphan" />

有时让其中一方(尤其多对多)放弃外键约束 inverse="true" (了解)

cascade和inverse的区别
    cascade用来级联操作(保存、修改和删除)           ★保存和删除数据的
    inverse用来维护外键的

多对多,一般设计为具体中间实体,变成两个一对多,hibernate的一对多就不深究了

项目文件下载

今日项目文件下载:直接下载hibernate02.zip       网盘备份下载


最后的配置  今天无非学个级联,详细琢磨了下各种级联的效果罢了。。完全不需要

<set name="linkmans" cascade="save-update,delete">
            <key column="custId"/>
            <one-to-many class="cn.ahpu.domain.Linkman"/>
</set>

<many-to-one name="customer" class="cn.ahpu.domain.Customer" column="custId" cascade="save-update"/>

小结:

save-update,保存此方后,自动保存(已近有就不用了,必要时更新下)此方的javabean对象主动set,add而关联的另一方的记录

delete:级联删除,只要加上,删除了此类的一条记录,与之关联的另一方就会被级联删除(千万不能双方都配置级联,顶多一方配置个,否则相互级联,一删全删)

ssh备考-02多表关联关系映射(一对一、一对多、多对多如何配置)相关推荐

  1. Mybatis中的关系映射(一对一,一对多,多对多)

    在网上寻了很久,大多数讲关系性的文章都是大篇幅的去将表照搬上来,本来就很生硬,此文就不在讲述关系性映射的具体实现,转而从浅层来讲讲其概念性. 1.1 关联关系概述 在关系型数据库中,多表之间存在着三种 ...

  2. Hibernate关联关系映射-----双向一对多/多对一映射配置

    转自:http://blog.csdn.net/yifei12315/article/details/6985194 /// Hibernate: /// 双向关联就是有"一对多" ...

  3. 【MySQL数据库之多表关联关系(一对一、一对多、多对多)】

    文章目录 多表关联关系的实现 多表关联关系的分类 一对多 多对多 一对一 多表关联关系的实现 外键是一列或一组列,用于强制两个表中的数据之间的链接. 在外键引用中,第一个表的主键列(或多个列)由第二个 ...

  4. 7. MyBatis多表查询 - 一对一 - 一对多 - 多对多

    7. MyBatis多表查询 - 一对一 - 一对多 - 多对多 前言 在前面的篇章,我们已经熟悉了单表查询,下面我们来看看如何进行 多表查询. 数据准备 create database if not ...

  5. Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作

    Python进阶----表与表之间的关系(一对一,一对多,多对多),增删改查操作,单表查询,多表查询 一丶表与表之间的关系 背景: ​ ​ ​  ​ ​ 由于如果只使用一张表存储所有的数据,就会操作数 ...

  6. SQLAlchemy_定义(一对一/一对多/多对多)关系

    SQLAlchemy_定义(一对一/一对多/多对多)关系 目录 Basic Relationship Patterns One To Many One To One Many To Many Basi ...

  7. mybatis的一对一 一对多 多对多

    mybatis的一对一 一对多 多对多 1.表 2.建表语句 order_t表 CREATE TABLE `order_t` ( `id` int(11) NOT NULL, `user_id` in ...

  8. django orm级联_Django数据表关联关系映射(一对一、一对多、多对多)

    我们知道涉及到数据表之间的对应关系就会想到一对一.一对多.多对多,在学习 MySQL 数据库时表关系设计是需要重点掌握的知识.Django 中定义了三种关系类型的字段用来描述数据库表的关联关系:一对多 ...

  9. 【SSH进阶之路】Hibernate映射——一对一单向关联映射(五)

    [SSH进阶之路]Hibernate基本原理(一) ,小编介绍了Hibernate的基本原理以及它的核心,采用对象化的思维操作关系型数据库. [SSH进阶之路]Hibernate搭建开发环境+简单实例 ...

最新文章

  1. 脑出血遇到深度学习,是否可以无所遁形?
  2. matlab genfunction,Keras / Python相当于nn工具箱中的Matlab的genFunction
  3. 项目经理的几个重要转变
  4. 顺序查找法,用函数实现。
  5. easyUI的combobox设置隐藏和显示
  6. Odoo10教程---模块化三:模型约束,高级视图,工作流,安全性,向导,国际化和报表等
  7. 文本文件上传漏洞[任意.绕过.解析]
  8. 顺序表操作集 (20 分)
  9. 老李分享:性能测试过程
  10. 国图软件无法生成地籍调查表
  11. c xaml语言教程,Xamarin XAML语言教程基础语法篇大学霸
  12. Java语言实现文本转语音
  13. 将bmp格式的图片反色
  14. 火山视频抖音版批量下载,一个脚本就够了,手把手教你批量下载抖音火山高清视频。
  15. 电脑计算机硬盘格式化,教你电脑怎么格式化本地磁盘
  16. 西北工业大学计算机毕业论文,西北工业大学本科生毕业设计(论文)工作管理办法.docx...
  17. vue文件在服务器上乱码,解决vue-pdf查看pdf文件及打印乱码的问题
  18. 如何在无线路由器下,再接无线路由器?
  19. 软件设计师 软考 真题练习 (三)
  20. 如何用保险抵御人生中的死亡风险【全攻略】

热门文章

  1. js给动态添加的元素添加属性
  2. Harmonyos官网申请的,HarmonyOS 2.0手机开发者Beta公测招募,普通用户有没有必要申请?...
  3. 关于自动驾驶高精定位的几大问题
  4. win10 系统恢复后右键一直转圈卡死
  5. 【论文精读3】MVSNet系列论文详解-P-MVSNet
  6. (json web token)JWT攻击
  7. OpenCV—python 自动色彩均衡(ACE)
  8. PKI体系简易JAVA实现(一):时间戳服务器TSA
  9. 详细的SQL注入相关的命令
  10. ES集群重新设置密码(第二次执行.elasticsearch-setup-passwords interactive报错)