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>

)