HIbernate知识点复习之三
案例需求描述:
存在着一个客户对应多个联系人的情况,单独在联系人管理模块中对联系人信息进行维护,功能包括:
对联系人信息进行增删改查
表关系分析:
一 概述:数据库中多表之间存在着三种关系:一对一 一对多 多对多 ,这也是系统设计中三种实体关系。
二 建表原则
1 一对多:在多的一方 创建外键指向一得一方的主键
2 多对多:创建一个中间表,中间表里创建至少两个字段作为外键,分别指向多对多双方的主键
3 一对一:
(1)主键对应:一方主键作为另一方主键
(2)唯一外键:一方创建外键字段 指向另一方的主键
三Hibernate通过java对象描述数据表的关系:
一 对 一
class A{ class B{
B b; A a;
getter和setter方法 getter和setter方法
} }
一 对 多
class A{ class B{
Set<B> b=new HashSet<B>(); A a;
getter和setter方法 getter和setter方法
} }
多 对 多
class A{ class B{
Set<B> b;=new HashSet<B>(); Set<A> a=new HashSet<A>();
getter和setter方法 getter和setter方法
} }
多表关系映射配置:
一 一对多配置
1. 一对多的一方:
头标签<set name="" cascade="" inverse=""></set>
<set>对应着一方实体中关联多方的set集合属性,如果是list集合属性,对应的就是<list>
<set>元素的属性:
(1)name(必填) :实体中对应的集合名称
(2) cascade级联操作属性:
<1>级联操作概念:级联操作是指当主控方执行 保存,更新,删除操作时,其关联对象(被控方)也执行相同的操作,简化操作,少写代码
<2>cascade属性值:
* save-update:级联保存更新
多表操作时,保存一方/主控方(如:客户)的内容,又更新多方(如:联系人)的信息
特性:1》只保存一方的问题
2》具有方向性,保存一方同时更新另一方
存在情况:当双方都设置了save-update,则会双方都会执行对应关联的sql语句,从而产生多余sql语句。
* delete:级联删除,删除一方的同时,也删除多方的信息
概述:使用JDBC删除客户和联系人时,如果有外键的关系是不可以删除的。但Hibernate可以实现这样的功能。
但使用Hibernate删除有关联关系对象(如,客户)的默认情况,会先将关联关系的外键设置为null,再删掉客户对象。
删除的方式:
1》客户一方不放弃维护外键 inverse="false" ,且没有设置删除级联,属于默认情况时,若直接删除客户则
会把客户的关联的外键 设置为null再删。
2》客户一方不放弃维护外键 inverse="false",设置了删除级联,若直接删除客户,会把客户关联的(在另一张表的)联系人信息也删掉
3》客户一方放弃维护外键 inverse="true" 时,必须要设置删除级联才可进行删除
* all:save-update + delete
(3)inverse:配置关系是否维护
<1>概述:双向关联会产生多余的sql语句,如下面的例子
//将2号联系人关联的客户改为2号客户
Customer customer = session.get(Customer.class,2L);
LinkMan linkMan = session.get(LinkMan.class,2L);
//双向关联
linkMan.setCustomer(customer);
customer.getLinkMans().add(linkMan);
此代码会出现两个重复(更新外键)的update语句,
原因为:进行双向维护关系时,持久态对象可自动更新到数据库,更新客户时会修改一次外键,
更新联系人时也会修改一次外键,从而产生多余的sql语句
解决方案:只需一方放弃外键维护权即可(inverse="true"),也就是说关系不是双方维护的,只需交给一方去维护即可
而一对多时,通常由多方进行关系维护(如老师对学生时,每个学生记住一个老师名字容易于一个老师记住全部学生名字)
<2>原则:必须要有一方维护关系,如在 一对多关系中,只能是一方 放弃维护关系(inverse="true"),多方不能放弃维护
<3>取值:默认值为false,代表不放弃外键维护权,true为放弃外键维护权
(4)区分cascade和 inverse:
casacde强调的是操作一个对象时,是否还操作其关联对象
inverse强调的是外键的维护权
<set>标签的子标签:
(1)<key column="" ></key> column对应关联多方(set方)的数据库的外键名称
(2)<one-to-many class=""/>class 对应关联多方的实体全类名
一对多中一方的配置示例:
<set name="linkMans" inverse="true" cascade="save-update"> //放弃维护权,级联保存更新
<key column="lkm_cust_id" />
<one-to-many class="XXXX.ZZZ.LinkMan"/>
</set>
2. 一对多的多方:
<many-to-one name="customer" column="lkm_cust_id" class="Customer" cascade="save-update"></many-to-one>
name:多方实体中关联对象的属性名称
column:关联实体的在数据库中对应的外键名
class:关联实体的全类名
cascade:级联设置
二多对多:
1. 多对多的配置:
(1)配置模板:
<set name="roles" table="sys_user_role" cascade="save-update">
<key column="user_id"></key>
<many-to-many class="xx.xxx.Role" column="role_id"></many-to-many>
</set>
(2)<set>标签:
name:关联另一方的集合属性名称
table:中间表名称
(3)<key>标签:
column:当前对象在中间表的外键名称
(4)<many-to-many>标签:
class:关联另一方的实体全类名
column:关联另一方对应的外键
2. 多对多的外键维护问题:
(1)概述:在多对多的保存操作中,如果进行双向关系维护,就必须要有一方放弃外键维护权。
原因分析: 因为中间表作为 关系维护纽带
若两张表都进行关系维护,则中间表的外键录入每次都不能确定唯一的 主键,会出现 2对1的尴尬,会报错:
解决方案为:
1 不书写维护双向关系代码
2 在某方配置文件中进行 inverse="true"配置
(2)总结:
一般是由被动方放弃,如用户对角色,角色是被选中,所以角色要放弃外键维护权。
但如果进行单向关系维护,就不需任意放弃外键维护权。
3. 多对多的级联配置:
多对多进行保存操作时,不可以保存一方,所以必须要进行保存更新级联配置(cascade="save-update")
4. 多对多的其他操作:
(1)删除用户关联的角色
//查询2号用户
User user = session.get(User.class,2L);
//查询1号联系人
Role role=session.get(Role.class,1L);
//操作集合,相当于操作中间表
user.getRoles().remove(role);
(2)将某个用户的角色改选
//查询2号用户
User user = session.get(User.class,2L);
//查询1号联系人
Role role=session.get(Role.class,1L);
//查询2号联系人
Role role2=session.get(Role.class,2L);
//操作集合,相当于操作中间表
user.getRoles().remove(role);
user.getRoles().add(role2);
(3)给某个用户添加新角色
//查询2号用户
User user = session.get(User.class,2L);
//查询1号联系人
Role role=session.get(Role.class,1L);
//操作集合,相当于操作中间表
user.getRoles().add(role);
一对多 和 多对多配置比较:
一 (Customer) 对 多(LinkMan)
private Set<LinkMan>linkMans=new HashSet<LinkMan>(); private Customer customer;
<set name="linkMans" inverse="false" cascade="save-update"> <many-to-one name="customer" column="lkm_cust_id" class="Customer" >
<key column="lkm_cust_id" /> </many-to-one>
<one-to-many class="LinkMan"/>
</set>
***
多(User) 对 多(Role)
private Set<Role>roles=new HashSet<Role>(); private Set<User>users=new HashSet<User>();
中间表只有两个字段:user_id和role_id
<set name="roles" table="sys_user_role" cascade="save-update"> <set name="users" table="sys_user_role" inverse="true">
<key column="user_id"></key> <key column="role_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many> <many-to-many class="User" column="user_id"></many-to-many>
</set> </set>
)
转载于:https://blog.51cto.com/14008076/2300315