IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Hibernate关联映射 -> 正文阅读

[Java知识库]Hibernate关联映射

Hibernate关联映射

关联映射大体分为

一对一的关联映射
一对多的关联映射
多对多的关联映射

关联的方向

及关联有方向,大抵意思是一方能够通过关联查到对方,

这就具备了单向关联,如果双方能互相查到,就可以称为双向关联

例:

public class Person {
	
	private int id;
	
	private String name;
	
	private IdCard card; 
	//Person中持有IdCard对象,建立了单向关联
....
}
public class IdCard {
	
	private int id;
	
	private String Numbers;
	//IdCard中没有Person,无法获取Person的信息
	//就是它和Person没有关联
	//所以Person和IdCard是单向关联
....
}

如果IdCard中有Person对象

public class IdCard {
	
	private int id;
	
	private String Numbers;
	
	private Person person;
	//在IdCard中也可以查到Person的信息,
    //所以IdCard类和Person类就建立了双向关联
....
}

这种关联很容易理解,

但是这只是在实体对象层面上的关联

数据库中的关联

一般以设置外键参照其他表的主键建立表与表的关联**(外键关联)**

但也可以将主键作为外键(既是PK,也是FK)与其他表的主键建立关联**(主键关联)**

取决于业务的选择,通常可以将这三大类关系按上述的关联进行划分

一对一关系映射

1.一对一单向主键关联
2.一对一双向主键关联
3.一对一单向外键关联
4.一对一双向外键关联
1.一对一单向主键关联

以Person类和IdCcard为例:

他们的实体类的关系如,是典型的单向关联

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dEPjjJOY-1630160728327)(F:\LocalTyproPictrue\ss1-16298934971211.png)]
请添加图片描述

数据库表的关系如

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HnvQ0IY4-1630160728330)(F:\LocalTyproPictrue\874710-20161203121004193-814894327.png)]
请添加图片描述

person表的id既是主键,又是外键,要参照idcard表的主键

所以person的主键必须和idcard的主键相同,建立了主键关联

public class Person {
	
	private int id;
	
	private String name;
	
	private IdCard idCard;
}
Person.hbm.xml
<class name="pojo.Person" table="t_person">
    <id name="id" type="int">
    <!-- 主键生成策略 -->
        <generator class="foreign">
            <!--,因为主键同时也是外键,所以主键的生成参照属性idCard的类型的主键-->
            <param name="property">idCard</param>
        </generator>
    </id>
        <!-- 实体类的属性 -->
    <property name="name" type="string"/>
    <!--constrained=true表明当前主键作为外键参照了idCard属性(的主键)-->        
    <one-to-one name="idCard" constrained="true"></one-to-one>
</class>
public class IdCard {
	
	private int id;
	
	private String cardNo;
....
}
<class name="pojo.IdCard" table="t_card">
        <id name="id" column="id">
            <!-- 主键生成策略 使用native -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>
</calss>                

测试:

IdCard card = new IdCard();
card.setCardNo("99999");

session.save(card);

Person person = new Person();
person.setName("杰洛特");
person.setIdCard(card);

session.save(person);
session.beginTransaction().commit();

生成表

Hibernate: 
    
    create table t_idcard (
       id integer not null auto_increment,
        cardNo varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_person (
       id integer not null,
        name varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_person                        //向t_person表中添加t_person的id外键参照t_idcard的id
       add constraint FKn42oi4jn933kff11t0rmgmv6a 
       foreign key (id) 
       references t_idcard (id)

插入语句

Hibernate:                    
    insert 
    into
        t_idcard
        (cardNo) 
    values
        (?)                        //save(card)插入,拿到ID将card持久化
Hibernate: 
    insert 
    into
        t_person
        (name, id) 
    values
        (?, ?)                   //Commit时,插入Person对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gDBaSOxe-1630160728332)(F:\LocalTyproPictrue\1231.png)]

请添加图片描述

加载

Person person = session.load(Person.class, 1);
		
System.out.println(person.getIdCard().getCardNo());

System.out.println(person);

结果

Hibernate: 
    select
        person0_.id as id1_2_0_,
        person0_.name as name2_2_0_ 
    from
        t_person person0_ 
    where
        person0_.id=?                 //先查t_person表
Hibernate: 
    select
        idcard0_.id as id1_1_0_,
        idcard0_.cardNo as cardno2_1_0_ 
    from
        t_idcard idcard0_             //再通过t_person的主键(也是外键)查idcard表
    where
        idcard0_.id=?                  
99999
Person [id=1, name=杰洛特, card=IdCard [id=1, Numbers=99999]]

2.一对一双向主键关联

同理将IdCard类的加上Person的属性,变成双向关联

public class IdCard {
	
	private int id;
	
	private String cardNo;
    
    private Person person;      //使idcard可以查到对应的person,是IdCard和Person变成双向关联
....
}
<class name="pojo.IdCard" table="t_card">
        <id name="id" column="id">
            <!-- 主键生成策略 使用native -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>				<!--谁持有关联,谁就维护关联,所以增加one-to-one标签-->
        <one-to-one name="person"></one-to-one>          <!--因为是主键关联,不需要指定column-->
</calss>  

实体类的关系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WoN6ugF1-1630160728334)(F:\LocalTyproPictrue\s22.png)]

请添加图片描述

数据库的关系图

请添加图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RYoQL5jn-1630160728336)(F:\LocalTyproPictrue\874710-20161203121004193-814894327-16298981374043.png)]

测试(同上):

Hibernate: 
    
    create table t_idcard (
       id integer not null auto_increment,
        cardNo varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_person (
       id integer not null,
        name varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_person 
       add constraint FKn42oi4jn933kff11t0rmgmv6a 
       foreign key (id) 
       references t_idcard (id)
Hibernate: 
    insert 
    into
        t_idcard
        (cardNo) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_person
        (name, id) 
    values
        (?, ?)       

生成的表并和数据的插入没有变化

加载:

IdCard idCard = session.load(IdCard.class, 1);
		
System.out.println(idCard.getPerson().getName());
		
System.out.println(idCard);
Hibernate: 
    select
        idcard0_.id as id1_1_0_,
        idcard0_.cardNo as cardno2_1_0_,
        person1_.id as id1_2_1_,
        person1_.name as name2_2_1_ 
    from
        t_idcard idcard0_ 
    left outer join
        t_person person1_ 
            on idcard0_.id=person1_.id 
    where
        idcard0_.id=?
杰洛特
IdCard [id=1, Numbers=99999]

成功的根据idCard的主键查出对应的person属性的信息

3.一对一单向外键关联

通过设定的外键(不是主键)来参照其他的表建立关系,一般使用在多对一的关系映射中,

因为他就是多对一的一个特例,如果多端控制为1个的话,那不就是一对一了吗,这里要注意站的角度问题,多对一重点在多端,如果是一对多的话,重点在一端,一端本来就是1了,就没有所谓的特例了,所以还是要到多端去设置让他唯一,这样就达到了一对一关系,因此上面说的是多对一的一个特例,这样解释应该清楚了。如何设置多端唯一呢,通过一个属性 unique=ture。这样就使一个Person对应唯一一个IdCard,因为外键唯一,其他记录无法插入相同的外键值

数据库关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RG8WYe40-1630160728337)(F:\LocalTyproPictrue\s33.png)]
请添加图片描述

实体对象关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Ukui05x-1630160728338)(F:\LocalTyproPictrue\s44.png)]
请添加图片描述

Person类和其映射文件hbm.xml

public class Person {
	
	private int id;
	
	private String name;
	
	private IdCard idCard;
....
}    
<class name="pojo.Person" table="t_person">
		<id name="id" type="int">
			<!-- 主键生成策略 -->
			<generator class="native">
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="name" type="string"/>
		<many-to-one name="idCard" uniqued="true"></many-to-one>
</class>

IdCard类

public class IdCard {
	
	private int id;
	
	private String cardNo;
....
}
<class name="pojo.IdCard" table="t_card">
        <id name="id" column="id">
            <!-- 主键生成策略 使用native -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>
</calss>    

测试生成表和记录

Hibernate: 
    
    create table t_idcard (
       id integer not null auto_increment,
        cardNo varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_person (
       id integer not null auto_increment,
        name varchar(255),
        idCard integer,                             //生成外键idCard
        primary key (id)
    ) engine=InnoDB

Hibernate: 
    
    alter table t_person 
       add constraint UK_c7ore53eylsbhkt2qt3sf28xl unique (idCard)  //添加唯一属性
Hibernate: 
    
    alter table t_person 
       add constraint FKmwhwiyh1l4gnux6mfegyx5ki8 
       foreign key (idCard)                              //设置idCard为外键参照t_idcard的主键id
       references t_idcard (id)

Hibernate: 
    insert 
    into
        t_idcard
        (cardNo) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_person
        (name, idCard) 
    values
        (?, ?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lCMdrbKK-1630160728339)(F:\LocalTyproPictrue\sadqweq.png)]
请添加图片描述

加载:

Person person = session.load(Person.class, 1);
		
System.out.println(person.getIdCard().getCardNo());
		
System.out.println(person);

结果:

Hibernate: 
    select
        person0_.id as id1_2_0_,
        person0_.name as name2_2_0_,
        person0_.idCard as idcard3_2_0_ 
    from
        t_person person0_ 
    where
        person0_.id=?
Hibernate: 
    select
        idcard0_.id as id1_1_0_,
        idcard0_.cardNo as cardno2_1_0_,
        person1_.id as id1_2_1_,
        person1_.name as name2_2_1_,
        person1_.idCard as idcard3_2_1_ 
    from
        t_idcard idcard0_ 
    left outer join
        t_person person1_ 
            on idcard0_.id=person1_.id 
    where
        idcard0_.id=?
99999
Person [id=1, name=杰洛特, card=IdCard [id=1, Numbers=99999]]
4.一对一双向外键关联

同样只需要修改

IdCard类,然后在其中添加person属性

public class IdCard {
	
	private int id;
	
	private String cardNo;
    
    private Person person;      //使idcard可以查到对应的person,是IdCard和Person变成双向关联
....
}
<class name="pojo.IdCard" table="t_card">
        <id name="id" column="id">
            <!-- 主键生成策略 使用native -->
            <generator class="native">
            </generator>        
        </id>
        <!-- 一些常规属性 -->
        <property name="cardNo"></property>				<!--谁持有关联,谁就维护关联,所以增加one-to-one标签-->
        <!-- 要注意property-ref这个属性,很重要,关键的地方就在这里。
        property-ref:指定关联类的属性名,这个属性将会和本类的主键相对应。如果没有指定,
        会使用对方关联类的主键来跟本类的主键比较,这里要注意不是关联表中的外键字段名。如果不指定这个属性,那么
        一对一默认会使用主键去做对比。相当于原本我们
        是可以通过本类的主键去和关联类的外键比较,然后来找到对应记录的,但是这里一对一中没有
        column属性,所以该方法行不通,因此就想出了这种办法,不跟外键比,也不能跟主键比(因为不是主键关系),那么
        就跟关联表中的一个属性比,也就是我们这个person中的idCard属性,为什么找得到呢,因为从person能找到idCard,那么
        person中的idCard中就会有对应的值,我们跟该值比,也就能找到对应的person了。
        class:person所在的类,这个也可以不写,hibernate会自动帮我们找到
         -->        
        <one-to-one name="person" property-ref="idCard" class="pojo.Person"/>
</calss>  

实体类图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6RiKORpf-1630160728340)(F:\LocalTyproPictrue\double2.png)]
请添加图片描述

数据库关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3zretRT-1630160728341)(F:\LocalTyproPictrue\s33-16299046543465.png)]
请添加图片描述

生成表:

Hibernate: 
    
    create table t_idcard (                                       //和单向外键关联的生成一模一样
       id integer not null auto_increment,
        cardNo varchar(255),
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_person (
       id integer not null auto_increment,
        name varchar(255),
        idCard integer,
        primary key (id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_person 
       add constraint UK_c7ore53eylsbhkt2qt3sf28xl unique (idCard)
Hibernate: 
    
    alter table t_person 
       add constraint FKmwhwiyh1l4gnux6mfegyx5ki8 
       foreign key (idCard) 
       references t_idcard (id)
Hibernate: 
    insert 
    into
        t_idcard
        (cardNo) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_person
        (name, idCard) 
    values
        (?, ?)       

加载:

Person person = session.load(Person.class, 1);
		
System.out.println(person.getIdCard().getCardNo());
		
System.out.println(person);

//---------------------------------------------------------
Hibernate: 
    select
        idcard0_.id as id1_1_0_,
        idcard0_.cardNo as cardno2_1_0_,
        person1_.id as id1_2_1_,
        person1_.name as name2_2_1_,
        person1_.idCard as idcard3_2_1_ 
    from
        t_idcard idcard0_ 
    left outer join
        t_person person1_ 
            on idcard0_.id=person1_.idCard 
    where
        idcard0_.id=?
杰洛特
IdCard [id=1, Numbers=99999]

一对多关系映射

1.多对一单向关联
2.一对多单向关联
3.多对一双向关联/一对多双向关联

一对多,多对一都是使用外键进行关联,故不存在主键关联

1.多对一的单向关联

例:User类关联多个Account,多个Account可以指向同一个User

public class User {
	
	private int id;
	
	private String name;   //User里不能查到Account
....
}
<class name="pojo.User" table="t_user">
		<id name="id" type="int" column="user_id">
			<!-- 主键生成策略 -->
			<generator class="native">
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="name" type="string" column="user_name" />
</class>
public class Account {
	
	private int id;
	
	private String anumber;
	
	private User owner;
    //多个Account可以对应一个User
....
}
<class name="pojo.Account" table="t_account">
		<id name="id" type="int" column="a_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="anumber" type="string" column="a_number" />
         <!--在本类的表中添加参照关联对象owner的类对应的表的主键的外键,命名为userid-->       
		<many-to-one name="owner" class="pojo.User" column="userid"></many-to-one>
</class>

实体关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kIn0I08O-1630160728342)(F:\LocalTyproPictrue\未命名文件(21)].png)
请添加图片描述

数据库表关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqkPPpKA-1630160728343)(F:\LocalTyproPictrue\duo.png)]
请添加图片描述

生成数据库表和插入数据

create table t_account (
       a_id integer not null auto_increment,
        a_number varchar(255),
        userid integer,
        primary key (a_id)
    ) engine=InnoDB
    Hibernate: 
    
    create table t_user (
       user_id integer not null auto_increment,
        user_name varchar(255),
        primary key (user_id)
    ) engine=InnoDB
    Hibernate: 
    
    alter table t_account 
       add constraint FKd6w5hyskogyl000dxman01e74 
       foreign key (userid) 
       references t_user (user_id)//设置t_account的userid为外键参照t_user的主键
User rich = new User();
rich.setName("理查");
		
session.save(rich);         //持久化User对象
		
Account a1 = new Account();
a1.setAnumber("1111");
a1.setOwner(rich);          //设置关联属性
		
Account a2 = new Account();
a2.setAnumber("2222");
a2.setOwner(rich);         //设置关联属性
				
session.save(a1);         //持久化Account对象
session.save(a2);         
Hibernate: 
    insert 
    into
        t_user
        (user_name)                   //为了持久化对象拿到ID发的insert语句,没有意义
    values
        (?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid)      //因为account持有关系,所以account维护关系,
                                //将外键userid设置为关联对象(owner)的主键id 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pP6bRQWF-1630160728344)(F:\LocalTyproPictrue\j11.png)]
请添加图片描述

加载:

Account a1 = session.load(Account.class, 1);
		
System.out.println(a1.getOwner().getName());
		
System.out.println(a1);
//---------------------------------------
Hibernate: 
    select
        account0_.a_id as a_id1_0_0_,
        account0_.a_number as a_number2_0_0_,
        account0_.userid as userid3_0_0_ 
    from
        t_account account0_ 
    where
        account0_.a_id=?
Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_name2_3_0_ 
    from
        t_user user0_ 
    where
        user0_.user_id=?
理查
Account [id=1, anumber=1111, owner=User [id=1, name=理查]]
2.一对多单的向关联

根据谁持有关系,谁就维护对象关系的原则,

上例中的单向多对一中的Account持有User的关联,所以就由多的一方Account维护关系,

而单向一对多则是多的一方没有关联,单的一方持有关联,如下

public class User {
	
	private int id;
	
	private String name;
	
    //持有对Account的关联
    private Set<Account> accounts;    
...
}        
	
<class name="pojo.User" table="t_user">
		<id name="id" type="int" column="user_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="name" type="string" column="user_name" />
         <!--关联属性-->      
         <set name="accounts">
                <!--给关联对象的类的表添加名为userid的外键约束-->
                <key column="userid" />
                <!--指定set集合中的类型为关联的对象的类型-->
                <one-to-many class="pojo.Account"></one-to-many>
         </set>
</class>
public class Account {
	
	private int id;
	
	private String anumber;
	
    //不持有关系,就不需要维护关系
....
}
<!--映射一个普通实体类-->
<class name="pojo.Account" table="t_account">
		<id name="id" type="int" column="a_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="anumber" type="string" column="a_number" />
</class>

数据库关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqaQ3zr9-1630160728345)(F:\LocalTyproPictrue\onetomany.png)]
请添加图片描述

实体类关系图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vmeTVZD4-1630160728345)(F:\LocalTyproPictrue\qis.png)]
请添加图片描述

生成表的语句

Hibernate: 
    
    create table t_account (
       a_id integer not null auto_increment,
        a_number varchar(255),
        userid integer,                           //t_user表向t_account表中插入了userid作为外键参照t_user的主键
        primary key (a_id)                        //但Account类并不知道自己的表中有userid字段
    ) engine=InnoDB                             
 Hibernate: 
    
    create table t_user (
       user_id integer not null auto_increment,
        user_name varchar(255),
        primary key (user_id)
    ) engine=InnoDB

Hibernate: 
    
    alter table t_account 
       add constraint FKd6w5hyskogyl000dxman01e74 //自动添加外键约束
       foreign key (userid) 
       references t_user (user_id)

插入相关数据:

User rich = new User();
rich.setName("理查");
session.save(rich);

Account a1 = new Account();
a1.setAnumber("1111");
		
Account a2 = new Account();
a2.setAnumber("2222");
		
		
session.save(a1);
session.save(a2);
		
Set<Account> accounts = new HashSet<>();
accounts.add(a1);
accounts.add(a2);
		
rich.setAccounts(accounts);

产生的sql语句:

Hibernate: 
    insert 
    into
        t_user
        (user_name) 
    values
        (?)         //为了设置ID主键发的insert语句,没有意义
Hibernate: 
    insert 
    into
        t_account
        (a_number) 
    values           //为了设置ID主键发的insert语句,没有意义,
        (?)          //因为Account并不持有和维护关联,所以不会去设置那个外键userid的值,此时userid字段为null
Hibernate: 
    insert 
    into
        t_account
        (a_number) 
    values            //同上
        (?)
Hibernate: 
    update
        t_account    //将account集合添加并commit后,User需要维护关系,将set集合类内的对象对应的表的外键(userid)
    set              //设置为t_user表的主键值,所以发起update的语句,将尚为null值的userid设置为t_user的主键值
        userid=?     //因此是主键主动关联外键,查询时自然也是主键查找外键(通过t_user的id查找t_account的userid)
    where
        a_id=?
Hibernate: 
    update
        t_account 
    set
        userid=? 
    where
        a_id=?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dy5WbCTv-1630160728346)(F:\LocalTyproPictrue\aw1-16299812980832.png)]
请添加图片描述

一对多单向关联的缺点

一.向关联表设置外键而关联类并不知道,每有一个关联类对象需要维护关系(getAccounts().add(Account对象)),就需要发一条update语句,增加了开销

二.若userid(外键)的属性为not null,则根本无法持久化account对象(无法插入t_aacount表)

3.一对多/多对一双向关联

在双向关联中多对一和一对多是相互的,因为双方都有关联,一方是一对多,多方是多对一,所以双向多对一和一对多是没有区别的。

有因为双方都持有关联,所以双方都要维护关系

public class User {
	
	private int id;
	
	private String name;
	//持有一对多的关系
	private Set<Account> accounts;
...
}
<class name="pojo.User" table="t_user">
		<id name="id" type="int" column="user_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="name" type="string" column="user_name" />
		<set name="accounts">  
			<key column="userid"></key>  <!--向关联类型Account类对应的表中设置名为userid的外键-->
			<one-to-many class="pojo.Account"/>
		</set>
</class>
public class Account {
	
	private int id;
	
	private String anumber;
	//持有多对一的关系
	private User owner;
..
}
<class name="pojo.Account" table="t_account">
		<id name="id" type="int" column="a_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="anumber" type="string" column="a_number" />
         <!--在本类对应的表中添加外键参照于关联对象owner对应的类(User)对应的表的主键(user_id)-->
         <!--column属性的值必须和一方关系set标签中的key标签的name属性相同,表示两个类设置的是同一个外键-->
         <!--如果column属性和对方key标签的name属性不同,则会设置两个外键(名字分别和column属性,key的name属性相同)--> 
		<many-to-one name="owner" class="pojo.User" column="userid"></many-to-one>
</class>

实体类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oQ3xPoNW-1630160728350)(F:\LocalTyproPictrue\dou.png)]
请添加图片描述

在实体类中双方都能够查到关联类的信息,具备了双向关联

数据库关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4TE19pTD-1630160728351)(F:\LocalTyproPictrue\d11.png)]
请添加图片描述

数据库的表并没有改变,只是双方对象都能够通过userid这个外键来维护关系

生成表的语句:

User rich = new User();
rich.setName("理查");
		
session.save(rich);
		
Account a1 = new Account();
a1.setAnumber("1111");
a1.setOwner(rich);
Account a2 = new Account();
a2.setAnumber("2222");
a2.setOwner(rich);
		
session.save(a1);
session.save(a2);
		
Set<Account> accounts = new HashSet<>();
accounts.add(a1);
accounts.add(a2);
		
rich.setAccounts(accounts);
Hibernate: 
    
    create table t_account (
       a_id integer not null auto_increment,
        a_number varchar(255),
        userid integer,                         
        primary key (a_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_user (
       user_id integer not null auto_increment,
        user_name varchar(255),
        primary key (user_id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_account 
       add constraint FKd6w5hyskogyl000dxman01e74            //设置userid为外键操作t_user的user_id
       foreign key (userid) 
       references t_user (user_id)
Hibernate: 
    insert 
    into
        t_user
        (user_name)               //持久化user为了拿到ID发的insert语句,没有意义
    values
        (?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid)        //持久化account对象时,因为设置了关联对象,account为了维护关系插入了外键userid  
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid)     //持久化account对象时,因为设置了关联对象,account为了维护关系插入了外键userid 
    values                
        (?, ?)
Hibernate: 
    update
        t_account            //commit提交后,因为设置了关联对象(setAccounts(Set<Account>)),user也要根据
    set                      //set集合内的关联对象(account对象)的类对应的表(t_account)的外键(userid)来关联
        userid=?             //t_user的user_id主键,即user也要维护关系,将account对象的外键设置为user的主键,
    where                    //故再次发出了两条update语句,但在之前account已经维护了关系(setOwner(user)),向                                    //t_account中插入了userid,所以这两条update语句是多余的
        a_id=?
Hibernate: 
    update
        t_account 
    set
        userid=? 
    where
        a_id=?
       

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WHctnRLb-1630160728352)(F:\LocalTyproPictrue\aw1-16299882575814.png)]
请添加图片描述

测试:

User user = session.load(User.class, 1);
		
Account a1 = session.load(Account.class, 1);
		
Set<Account> announces = user.getAccounts();        //拿到user的用户集合属性
		
announces.forEach(announce->System.out.println(announce)); //输出
		
System.out.println(a1.getOwner().getName());

结果:

Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_ 
    from
        t_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        accounts0_.userid as userid3_0_0_,
        accounts0_.a_id as a_id1_0_0_,
        accounts0_.a_id as a_id1_0_1_,
        accounts0_.a_number as a_number2_0_1_,
        accounts0_.userid as userid3_0_1_ 
    from
        t_account accounts0_ 
    where
        accounts0_.userid=?
Account [id=2, anumber=2222]
Account [id=1, anumber=1111]
理查

4.inverse和cascade的使用

双向的一对多/多对一双向的多对多的关系中,双方都持有关联属性的关系,就像上例中的User和account,

更具谁持有关系,谁就维护关系的原则,双方都要维护关系,

account一方维护了关系,向外建useid插入关联类的id,

user也维护了关系,更新set中关联属性对象的外键为本类对象的主键的值

这也就造成了后面的那两条多余的update语句

虽然没有出现错误,但显然降低了效率

使用inverse属性来指定哪一方来维护关联关系

inverse的默认为false

inverse只存在于集合标记的元素中

Hibernate提供的集合元素包括

inverse=“true”,表示这一方放弃维护关系,由另一方来维护关系

例:将双向一对多/多对一关联的1的一方设置inverse=“true”,将关系交给多的一方维护,只需将上例稍微改造,代码如下

<class name="pojo.User" table="t_user">
		<id name="id" type="int" column="user_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="name" type="string" column="user_name" />
		<set name="accounts" inverse="true">            <!--在多的一方的关联关系中加上inverse="true"-->
			<key column="userid"></key>
			<one-to-many class="pojo.Account"/>
		</set>
</class>

将表删除,重新插入数据,生成的sql语句如下

User rich = new User();
rich.setName("理查");
		
session.save(rich);
		
Account a1 = new Account();
a1.setAnumber("1111");
a1.setOwner(rich);
Account a2 = new Account();
a2.setAnumber("2222");
a2.setOwner(rich);
		
session.save(a1);
session.save(a2);
		
Set<Account> accounts = new HashSet<>();
accounts.add(a1);
accounts.add(a2);
		
rich.setAccounts(accounts);                   //插入数据的代码没变,但是却少了那两条update语句
                                              //说明user对象没有根据设置关联对象去维护关系,
                                              //这就是inverse的作用
//---------------------------------------------
Hibernate: 
    insert 
    into
        t_user
        (user_name) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)

由于user并不维护关系,所以只需要通过account(多的一方)来维护关系即可,可以将插入数据的代码改为,删表重新运行

User rich = new User();
rich.setName("理查");
		
session.save(rich);
		
Account a1 = new Account();
a1.setAnumber("1111");
a1.setOwner(rich);
Account a2 = new Account();
a2.setAnumber("2222");
a2.setOwner(rich);
		
session.save(a1);
session.save(a2);
		
//Set<Account> accounts = new HashSet<>();
//accounts.add(a1);
//accounts.add(a2);
		
//rich.setAccounts(accounts); 

结果为:

Hibernate: 
    
    create table t_account (
       a_id integer not null auto_increment,
        a_number varchar(255),
        userid integer,
        primary key (a_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_user (
       user_id integer not null auto_increment,
        user_name varchar(255),
        primary key (user_id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_account 
       add constraint FKd6w5hyskogyl000dxman01e74 
       foreign key (userid) 
       references t_user (user_id)

Hibernate: 
    insert 
    into
        t_user
        (user_name) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E4F0ytRx-1630160728352)(F:\LocalTyproPictrue\aw1-16299935617955.png)]
请添加图片描述

依然一样,所以确定user并没有维护关系,

这样一来,就像多对一单向关联一样,只需要多的一方维护关系就可以了

但单向关联user是不可以查到account的,

来实验以下看看user在inverse="true"的情况是是否能够查到accounts集合

在相同的测试代码中,结果也是一样

User user = session.load(User.class, 1);
		
Account a1 = session.load(Account.class, 1);
		
Set<Account> announces = user.getAccounts();
		
announces.forEach(announce->System.out.println(announce));
		
System.out.println(a1.getOwner().getName());
//------------------------------------------------------------
Hibernate: 
    select
        user0_.user_id as user_id1_3_0_,
        user0_.user_name as user_nam2_3_0_     //查询t_user表的信息
    from
        t_user user0_ 
    where
        user0_.user_id=?
Hibernate: 
    select
        accounts0_.userid as userid3_0_0_,
        accounts0_.a_id as a_id1_0_0_,
        accounts0_.a_id as a_id1_0_1_,
        accounts0_.a_number as a_number2_0_1_,
        accounts0_.userid as userid3_0_1_ 
    from
        t_account accounts0_ 
    where
        accounts0_.userid=?           //更具user的id去account表中查找外键(userid)与user_id相同的account信息     
Account [id=2, anumber=2222]
Account [id=1, anumber=1111]
理查

所以只要由一方来维护关系就可以达到双向关联了,

又因为一对多中由1方来维护关系的效率不高,所以在大多数的双向多对一/一对多的关联中应该让1方放弃维护关系(设置inverse=“true”),而由多的一方来维护关系

cascade

cascade属性的作用是描述关联对象进行操作时的级联特性。因此,只有涉及到关系的元素才有cascade属性。

具 有cascade属性的标记包括

注意:和 是用在集合标记内部的,所以是不需要cascade属性的。

级联操作:指当主控方执行某项操作时,是否要对被关联方也执行相同的操作。

如上例的account类的owner属性在hbm.xml中添加上级联属性,

<class name="pojo.Account" table="t_account">
		<id name="id" type="int" column="a_id">
			<!-- 主键生成策略 -->
			<generator class="native">
				
			</generator>
		</id>
		<!-- 实体类的属性 -->
		<property name="anumber" type="string" column="a_number" />
		<many-to-one name="owner" class="pojo.User" column="userid" cascade="all"></many-to-one>
</class>
User rich = new User();
rich.setName("理查");
		
//session.save(rich);                 //将持久化对象的语句注释掉然后删表再运行
		
Account a1 = new Account();
a1.setAnumber("1111");
a1.setOwner(rich);                   //设置关联对象
Account a2 = new Account();
a2.setAnumber("2222");
a2.setOwner(rich);                    //设置关联对象
		
session.save(a1);
session.save(a2);
		

结果:

Hibernate: 
    insert 
    into
        t_user
        (user_name)                    //并没有通过Session去持久化user对象,但数据库依然插入了user的记录
    values                             //如果没有cascade属性,一定会出现瞬时态对象异常TrainsacObjectException
                                       //因为它并没有纳入session缓存(没有ID属性)
        (?)                            //所以cascade="all"一定调用save方法持久化了user对象
Hibernate:                             //由此在持久化account对象时,cascade检查了其关联的user对象,并将其也持久化
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_account
        (a_number, userid) 
    values
        (?, ?)

cascade的可选值

1.all: 所有情况下均进行关联操作,即save-update和delete。
2.none: 所有情况下均不进行关联操作。这是默认值。
3.save-update: 在执行save/update/saveOrUpdate时进行关联操作。
4.all-delete-orphan: 当一个节点在对象图中成为孤儿节点时,删除该节点

?

其他应该度知道,说一下这个all-delete-orphan:什么是孤儿节点,举个例子,班级和学生,一张classes表,一张student表,student表中有5个学生的数据,其5个学生都属于这个班级,也就是这5个学生中的外键字段都指向那个班级,现在删除其中一个学生(remove),进行的数据操作仅仅是将student表中的该学生的外键字段置为null,也就是说,则个学生是没有班级的,所以称该学生为孤儿节点,我们本应该要将他完全删除的,但是结果并不如我们所想的那样,所以设置这个级联属性,就是为了删除这个孤儿节点。也就是解决这类情况。

多对多关系映射

1.多对多单向关联

以经典的学生选课为例:

public class Student {
	
	private int id;
	
	private String name;
	
	private boolean sex;
	
	private Set<Course> courses;
	...
	}
//-----------------------------
<class name="pojo.Student" table="t_student">
		<id name="id" column="student_id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="student_name"></property>
		<property name="sex" column="student_sex"></property>
         <!--维护多对多的关系,指定中间表-->       
		<set name="courses" table="t_student_course">
             <!--设置中间表的外键关联本类的主键(s_id)-->   
			<key column="s_id"></key>
             <!--多对多标签,指定关联类在中间表的外键名称(c_id)-->   
			<many-to-many class="pojo.Course" column="c_id"></many-to-many>
		</set>
</class>
public class Course {
	
	private int id;
	
	private String name;
...
}
//----------------------------------
<class name="pojo.Course" table="t_course">
    	<!--普通类的映射-->
		<id name="id" column="Course_id">
			<generator class="native"></generator>
		</id>
		<property name="name" column="Course_name"></property>
</class>

数据库关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p9RGiMqm-1630160728353)(F:\LocalTyproPictrue\llc.png)]
请添加图片描述

实体类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BAK0hCNx-1630160728354)(F:\LocalTyproPictrue\ops.png)]
请添加图片描述

生成表并插入数据:

Student s1 = new Student();
s1.setName("张三");
s1.setSex(true);
		
Student s2 = new Student();
s2.setName("李四");
s2.setSex(true);
		
Course c1 = new Course();
c1.setName("语文");
		
Course c2 = new Course();
c2.setName("数学");
		
Course c3 = new Course();
c3.setName("英语");
		
session.save(s1);
session.save(s2);
		
session.save(c1);session.save(c2);session.save(c3);
Set<Course> set1 = new HashSet<>();set1.add(c1);set1.add(c2);
		
Set<Course> set2 = new HashSet<>();set2.add(c1);set2.add(c2);set2.add(c3);
		
s1.setCourses(set1);  //设置关联属性
s2.setCourses(set2);
Hibernate: 
    
    create table t_course (
       Course_id integer not null auto_increment,              //课程表
        Course_name varchar(255),
        primary key (Course_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_student (
       student_id integer not null auto_increment,            //学生表    
        student_name varchar(255),
        student_sex bit,
        primary key (student_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_student_course (                          //中间表
       s_id integer not null,
        c_id integer not null,
        primary key (s_id, c_id)                             //设置联合主键
    ) engine=InnoDB
Hibernate: 
    
    alter table t_student_course 
       add constraint FK4ofi7wwyawdxj17rva1qlrqn             //添加外键关联
       foreign key (c_id) 
       references t_course (Course_id)
Hibernate: 
    
    alter table t_student_course                            //添加外键关联
       add constraint FKbphe0lu2o1xuves08sgj835ka 
       foreign key (s_id) 
       references t_student (student_id)
Hibernate: 
    insert 
    into
        t_student
        (student_name, student_sex)            //持久化,生成学生对象的ID
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (student_name, student_sex)            //持久化,生成学生对象的ID
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name)                            //持久化,生成课程对象的ID
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name)                            //持久化,生成课程对象的ID
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name)                             //持久化,生成课程对象的ID
    values
        (?)
//--------------------------------------------------------分割线,下面是student维护关系对中间表插入了5条数据        
Hibernate: 
    insert 
    into
        t_student_course                         //设置多对多的关联信息,向关联表t_student_cource插入数据
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3bGfjqXA-1630160728355)(F:\LocalTyproPictrue\t33.png)]
请添加图片描述

加载:

Student s1 = session.load(Student.class, 1);

Set<Course> courses = s1.getCourses();

courses.forEach(course->{System.out.println(course);});

System.out.println(s1.getName()+s1.getId());
//------------------------------------------
Hibernate: 
    select
        student0_.student_id as student_1_4_0_,
        student0_.student_name as student_2_4_0_,
        student0_.student_sex as student_3_4_0_ 
    from
        t_student student0_ 
    where
        student0_.student_id=?
Hibernate: 
    select
        courses0_.s_id as s_id1_5_0_,
        courses0_.c_id as c_id2_5_0_,
        course1_.Course_id as course_i1_1_1_,
        course1_.Course_name as course_n2_1_1_ 
    from
        t_student_course courses0_ 
    inner join
        t_course course1_ 
            on courses0_.c_id=course1_.Course_id 
    where
        courses0_.s_id=?
Course [id=1, name=语文]
Course [id=2, name=数学]
张三1
2.多对多双向关联

无非是在Cource课程类中也可以查到Student类的信息

public class Course {
	
	private int id;
	
	private String name;
    
    private Set<Student> students;
...
}
//----------------------------------
<class name="pojo.Course" table="t_course">
    <id name="id" column="Course_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="Course_name"></property>
    <!--指定中间表,设置中间表的c_id为本类ID的外键-->
    <set name="students" table="t_student_cource">
        <key column="c_id"></key>
        <!--设置集合中的类型,和其对应表的主键在中间表的外键字段-->
        <many-to-many class="pojo.Student" column="s_id"></many-to-many>
    </set>
</class>

数据库关系图不变,

实体类关系图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOQxtUGJ-1630160728356)(F:\LocalTyproPictrue\aos1.png)]
请添加图片描述

重新创建表并插入语句:

System.out.println("多对多测试");

		
Student s1 = new Student();                //学生张三,李四
s1.setName("张三");
s1.setSex(true);
		
Student s2 = new Student();
s2.setName("李四");
s2.setSex(true);
		
Course c1 = new Course();                 //课程语文数学英语
c1.setName("语文");
		
Course c2 = new Course();
c2.setName("数学");
		
Course c3 = new Course();
c3.setName("英语");
		
session.save(s1);
session.save(s2);
		
session.save(c1);session.save(c2);session.save(c3);
Set<Course> set1 = new HashSet<>();set1.add(c1);set1.add(c2);
Set<Course> set2 = new HashSet<>();set2.add(c1);set2.add(c2);set2.add(c3);
		
//		Set<Student> StuSet = new HashSet<>();StuSet.add(s1);StuSet.add(s2);     //运行时是没有注释这些代码的
//		Set<Student> StuSet2 = new HashSet<>();StuSet.add(s1);            //为的是让他们双方都去维护多对多关系
		
s1.setCourses(set1);
s2.setCourses(set2);
		
//		c1.setStudents(StuSet);
//		c2.setStudents(StuSet);
//		c3.setStudents(StuSet2);

结果:

出现异常
MySQL:Duplicate entry '1-2' for key 'PRIMARY' 错误

这是因为在默认情况下n-n的两端都会维护关联关系,当执行上述代码后,student要维护关联关系,往连接表中添加5条记录,然后cource也要维护关联关系,往连接表中添加相同的5条记录,
会导致连接表中主键重复,

结论:

双向多对多关联无法在双方都维护关系的情况下设置双向关联

当删除上一个代码块中的注释语句后,程序正常运行。

结果如下:

Hibernate: 
    
    create table t_course (
       Course_id integer not null auto_increment,
        Course_name varchar(255),
        primary key (Course_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_student (
       student_id integer not null auto_increment,
        student_name varchar(255),
        student_sex bit,
        primary key (student_id)
    ) engine=InnoDB
Hibernate: 
    
    create table t_student_course (
       s_id integer not null,
        c_id integer not null,
        primary key (c_id, s_id)
    ) engine=InnoDB
Hibernate: 
    
    alter table t_student_course 
       add constraint FK4ofi7wwyawdxj17rva1qlrqn 
       foreign key (c_id) 
       references t_course (Course_id)
Hibernate: 
    
    alter table t_student_course 
       add constraint FKbphe0lu2o1xuves08sgj835ka 
       foreign key (s_id) 
       references t_student (student_id)
八月 28, 2021 9:36:25 下午 org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: 
    insert 
    into
        t_student
        (student_name, student_sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student
        (student_name, student_sex) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_course
        (Course_name) 
    values
        (?)
//--------------------------------------------------------分割线,下面是student维护关系对中间表插入了5条数据        
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_student_course
        (s_id, c_id) 
    values
        (?, ?)

加载:

Course c1 = session.get(Course.class, 1);
		
Set<Student> students = c1.getStudents();
		
students.forEach(student->{System.out.println(student.getId()+student.getName()+student.isSex());});
		
System.out.println(c1.getName());
//----------------------------------------------
Hibernate: 
    select
        course0_.Course_id as course_i1_1_0_,
        course0_.Course_name as course_n2_1_0_ 
    from
        t_course course0_ 
    where
        course0_.Course_id=?
Hibernate: 
    select
        students0_.c_id as c_id2_5_0_,
        students0_.s_id as s_id1_5_0_,
        student1_.student_id as student_1_4_1_,
        student1_.student_name as student_2_4_1_,
        student1_.student_sex as student_3_4_1_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.s_id=student1_.student_id 
    where
        students0_.c_id=?
1张三true
2李四true
语文

正确的查出了数据

建议:

既然双向多对多无法同时由双方一起维护关系,

那么就应该设置任意一方的关联属性为inverse=“true”,使操作类似于单向多对多

感想:

将关系映射,根据方向,类型进行分类更有利于理解和应用Hibernate的相关技术

_course
(Course_name)
values
(?)
Hibernate:
insert
into
t_course
(Course_name)
values
(?)
//--------------------------------------------------------分割线,下面是student维护关系对中间表插入了5条数据
Hibernate:
insert
into
t_student_course
(s_id, c_id)
values
(?, ?)
Hibernate:
insert
into
t_student_course
(s_id, c_id)
values
(?, ?)
Hibernate:
insert
into
t_student_course
(s_id, c_id)
values
(?, ?)
Hibernate:
insert
into
t_student_course
(s_id, c_id)
values
(?, ?)
Hibernate:
insert
into
t_student_course
(s_id, c_id)
values
(?, ?)


加载:

```java
Course c1 = session.get(Course.class, 1);
		
Set<Student> students = c1.getStudents();
		
students.forEach(student->{System.out.println(student.getId()+student.getName()+student.isSex());});
		
System.out.println(c1.getName());
//----------------------------------------------
Hibernate: 
    select
        course0_.Course_id as course_i1_1_0_,
        course0_.Course_name as course_n2_1_0_ 
    from
        t_course course0_ 
    where
        course0_.Course_id=?
Hibernate: 
    select
        students0_.c_id as c_id2_5_0_,
        students0_.s_id as s_id1_5_0_,
        student1_.student_id as student_1_4_1_,
        student1_.student_name as student_2_4_1_,
        student1_.student_sex as student_3_4_1_ 
    from
        t_student_course students0_ 
    inner join
        t_student student1_ 
            on students0_.s_id=student1_.student_id 
    where
        students0_.c_id=?
1张三true
2李四true
语文

正确的查出了数据

建议:

既然双向多对多无法同时由双方一起维护关系,

那么就应该设置任意一方的关联属性为inverse=“true”,使操作类似于单向多对多

感想:

将关系映射,根据方向,类型进行分类更有利于理解和应用Hibernate的相关技术

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-29 08:57:09  更:2021-08-29 08:59:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 12:48:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码