关系映射
实体之间的关系:
一对多:用户和订单 分类和商品 订单和订单项 客户和联系人
多对多:订单和商品 学生和课程 角色和用户
一对一:夫妻 居民和身份证号
表关系设计:
一对多:
在多表上添加一个外键字段.
多对多:
添加一张中间表,表中保留另外两张表的主键作为外键.就可以将多对多拆成两个一对多. 中间表都是多的一方
一对一:
解决方案:
1.两个实体合二为一
2.唯一外键对应(把一张表作为多表,添加外键约束,再在外键上添加唯一约束即可)
3.主键对应(只需要在其中一张表上,给主键添加外键约束即可)
javabean的关系设计:
一对多:
我们可以根据需要:
在一的一方添加多的一方的集合
在多的一方添加一的一方的对象
多对多:
添加一个对方的集合
一对一:
添加一个对方的对象
hibernate中一对多★★
客户和联系人
步骤:
1.新建数据库
create database hibernate03;
use hibernate03;
2.设计javabean
客户:
添加一个联系人的集合
联系人:
添加一个客户的对象
3.编写映射文件
多的一方
many-to-one标签:
name:一的一方在多的一方中对象属性名称
class:一的一方的全限定名
column:外键字段名称
多的一方domain代码:
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
//用来表示属于那个客户
//private String lkm_cust_id;
private Customer customer;
多的一方配置文件:
<!-- 配置映射关系
name:一的一方在多的一方中对象属性名称
class:一的一方的全限定名
column:外键字段名称
-->
<many-to-one name="customer" class="com.xx.domain.Customer" column="lkm_cust_id"/>
一的一方,配置文件
set标签:
name属性:多的一方在一的一方中集合属性名称
key标签:
coluomn属性:外键的字段名称
one-to-many标签:
class属性:多的一方的全限定名
代码:
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
//表示当前客户拥有的联系人
private Set<Linkman> linkmans = new HashSet<>();
配置文件
<!-- 配置映射关系
name:多的一方在一的一方中集合属性名称名称
-->
<set name="linkmans" cascade="save-update,delete" inverse="true">
<!--
column:外键字段名称
-->
<key column="lkm_cust_id"/>
<!--
class:多的一方的全限定名
-->
<one-to-many class="com.xx.domain.Linkman"/>
</set>
注意:
别忘记在核心配置文件中加载两个映射文件
测试
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//创建1个客户(浩总)
Customer c2 = new Customer("浩总");
//创建1个联系人(浩秘书)
Linkman l3 = new Linkman("浩秘书");
//双向关联
c2.getLinkmans().add(l3);
l3.setCustomer(c2);
//保存
session.save(c2);//只保存客户的时候,能不能将关联的联系人一并保存呢??不行,报瞬时对象异常错误
tx.commit();
保存客户的同时,将其联系人一并保存:
客户是主体,需要在主体一方的映射文件中设置级联操作 set标签上配置一个属性 cascade=”save-update”
<set name="linkmans" cascade="save-update,delete">
级联操作:
级联:操作主体的时候,顺便将其关联的对象进行同样的操作
级联具有方向性
级联保存更新:
保存客户的同时,将其联系人一并保存:
客户是主体,需要在主体一方的映射文件中设置级联操作 set标签上配置一个属性 cascade=”save-update”
保存联系人的同时,将其客户一并保存:
联系人是主体,需要在主体一方的映射文件中设置级联操作 many-to-one标签上配置一个属性 cascade=”save-update”
级联删除
删除主表中已被引用的数据:
★★先把从表中的指定的外键置为null,然后再删除主表中相应的记录
级联删除:
★★删除客户的同时,将其联系人一并删除:
客户是主体,需要在主体一方的映射文件中设置级联操作 set标签上配置一个属性 cascade=”delete” 或者 cascade=”save-update,delete”
删除联系人的同时,将其客户一并删除
联系人是主体,需要在主体一方的映射文件中设置级联操作 many-to-one标签上配置一个属性 cascade=”save-update,delete”
冗余sql(多余sql)
在测试保存的时候,保存一的一方,然后再保存多的一方,多发送了几条update语句.
他不影响结果.原因:双方都维护了外键.
开发中让一的一方放弃外键维护权
在一的一方的映射文件中的set标签上配置 inverse=”true”
<set name="linkmans" cascade="save-update,delete" inverse="true">
hibernate中多对多★
步骤:
1.创建实体
用户和角色
放入对方的集合
2.编写映射文件
set标签:
name属性:对方的集合属性名称
table属性:中间表表名
key标签
coluomn属性:自己在中间表的外键信息
many-to-many标签
class属性:对方的全限定名
column属性:对方在中间表中的外键信息
注意:在核心配置文件中配置映射文件
3.测试保存
开发中让被动方放弃
在角色的映射文件中配置 inverse=”true”
role类的映射文件配置:
<set name="users" table="sys_user_role" inverse="true">
<key column="role_num"/>
<many-to-many class="com.itheima.domain.User" column="user_num"/>
</set>
User类的文件配置
<!-- 映射关系
name:对方的集合属性名称
table:中间表表名
-->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!-- key标签中column:自己在中间表中的外键字段名称 -->
<key column="user_num"/>
<!--
class:对方的全限定名
column:对方在中间表中的外键字段名称
-->
<many-to-many class="com.itheima.domain.Role" column="role_num"/>
</set>
级联操作:
多对多 几乎用不上
级联保存更新:(知道 理解)
保存用户的时候将其关联的角色一并保存
用户是主体,需要在主体一方的映射文件中设置级联操作 set标签配置 cascade=”save-update”
级联删除(了解,用不上)
删除用户的同时将其关联的角色一并删除
用户是主体,需要在主体一方的映射文件中设置级联操作 set标签配置 cascade=”save-update,delete”
默认删除:★★
先删除中间表中的相应的记录
然后在删除对应表的相应记录
其他操作:(orm框架)
给用户添加角色
获取角色集合 给集合添加一个角色
给用户删除角色
给用户修改角色
添加角色代码如下:
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取小青
User user = session.get(User.class,1L);
//获取员工
Role role = session.get(Role.class, 3L);
//给小青添加员工角色
user.getRoles().add(role);
tx.commit();
对象导航查询:
前提:
有关联关系
客户1 有几个联系人?
Customer c1 = session.get(Customer.class,1L);
c1.getLinkmans().size();
联系人1的客户名称是啥?
Linkman lk1 = session.get(Linkman.class,1L);
lk.getCustomer().getCust_name();
延迟加载:
用的时候才发送sql语句查询数据
作用:提高效率
★开发中
通过一的一方查询多的一方的时候 一般使用懒加载(默认值)
要想改变
在一的一方的映射关系中配置 lazy属性=false
常见值:
false:理解加载
true:默认值 懒加载
★开发中:
通过多的一方查询一的一方时候,一般都会查询一的一方
需要在多的一方的映射关系上设置 lazy属性:false
扩展:延迟加载:
类级别延迟加载(load)
关闭类级别的延迟加载方式
方式1:在类上加final
方式2:通过配置文件的方式修改 映射文件的class标签上有一个lazy属性 默认:true
关联级别的延迟加载
通过一个对象查询其关联对象是否采用延迟加载
在多的一方的映射关系上lazy属性的取值
false:立即加载
proxy:默认值 代理
是否采用延迟加载取决于一的一方的类级别的延迟加载
若一的一方的类级别的 lazy=true proxy就是延迟加载
若一的一方的类级别的 lazy=false proxy就是立即加载
总结:
实体之间的关系与设计
★★hibernate中的一对多
实体:
根据需要
在一的一方添加多的一方的集合
在多的一方添加一的一方的对象
映射文件:
在多的一方配置
many-to-one标签
name属性
class属性
column属性
在一的一方配置
set标签
name属性
key标签
column属性
one-to-many标签
class属性
级联:
具有方向性 操作主体的时候,将其关联的对象进行相同的操作
级联保存更新
在主体上配置 cascade=”save-update”
级联删除
在主体上配置 cascade=”delete”
默认删除
删除已被引用的一的一方
先把从表中的指定的外键置为null 再删除主表中记录
冗余sql:
让一的一方放弃外键维护权
set标签上 inverse=”true”
★hibernate中的多对多
实体:
放入对象的集合
映射文件
set标签
name属性
table属性
key标签
column属性
many-to-many标签
class属性
column属性
测试保存:
让被动方放弃外键维护权
级联操作几乎用不上
默认删除:
先删除中间表中的相应的记录,再删除相应表中记录
对象导航:
延迟加载:
需要的时候才发送sql语句
通过一的一方查询多的一方的时候,一般使用默认值 延迟加载
通过多的一方查询一的一方时候,一般使用理解加载
在多的一方的上配置 lazy=false