1、一对多关系
直接上一对多关系的相关代码
此处代码中所使用的表结构为客户表和联系人表,其中客户表为主表,联系人为从表
/**
* 客户的实体类
*/
public class Customer implements Serializable {
private Long custId;
private String custName;
private String custSource;
private String custIndustry;
private String custLevel;
private String custAddress;
private String custPhone;
//一对多关系映射:一个客户可以对应多个联系人
private Set<LinkMan> linkmans = new HashSet<LinkMan>();
public Long getCustId() {
return custId;
}
public void setCustId(Long custId) {
this.custId = custId;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustIndustry() {
return custIndustry;
}
public void setCustIndustry(String custIndustry) {
this.custIndustry = custIndustry;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustAddress() {
return custAddress;
}
public void setCustAddress(String custAddress) {
this.custAddress = custAddress;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public Set<LinkMan> getLinkmans() {
return linkmans;
}
public void setLinkmans(Set<LinkMan> linkmans) {
this.linkmans = linkmans;
}
@Override
public String toString() {
return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource
+ ", custIndustry=" + custIndustry + ", custLevel=" + custLevel + ", custAddress=" + custAddress
+ ", custPhone=" + custPhone + "]";
}
}
/**
* 联系人的实体类(数据模型)
*/
public class LinkMan implements Serializable {
private Long lkmId;
private String lkmName;
private String lkmGender;
private String lkmPhone;
private String lkmMobile;
private String lkmEmail;
private String lkmPosition;
private String lkmMemo;
//多对一关系映射:多个联系人对应客户
private Customer customer;//用它的主键,对应联系人表中的外键
public Long getLkmId() {
return lkmId;
}
public void setLkmId(Long lkmId) {
this.lkmId = lkmId;
}
public String getLkmName() {
return lkmName;
}
public void setLkmName(String lkmName) {
this.lkmName = lkmName;
}
public String getLkmGender() {
return lkmGender;
}
public void setLkmGender(String lkmGender) {
this.lkmGender = lkmGender;
}
public String getLkmPhone() {
return lkmPhone;
}
public void setLkmPhone(String lkmPhone) {
this.lkmPhone = lkmPhone;
}
public String getLkmMobile() {
return lkmMobile;
}
public void setLkmMobile(String lkmMobile) {
this.lkmMobile = lkmMobile;
}
public String getLkmEmail() {
return lkmEmail;
}
public void setLkmEmail(String lkmEmail) {
this.lkmEmail = lkmEmail;
}
public String getLkmPosition() {
return lkmPosition;
}
public void setLkmPosition(String lkmPosition) {
this.lkmPosition = lkmPosition;
}
public String getLkmMemo() {
return lkmMemo;
}
public void setLkmMemo(String lkmMemo) {
this.lkmMemo = lkmMemo;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
@Override
public String toString() {
return "LinkMan [lkmId=" + lkmId + ", lkmName=" + lkmName + ", lkmGender=" + lkmGender + ", lkmPhone="
+ lkmPhone + ", lkmMobile=" + lkmMobile + ", lkmEmail=" + lkmEmail + ", lkmPosition=" + lkmPosition
+ ", lkmMemo=" + lkmMemo + "]";
}
}
映射关系配置文件:
客户实体类配置文件:
<?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 package="com.itheima.domain">
<class name="Customer" table="cst_customer">
<id name="custId" column="cust_id">
<generator class="native"></generator>
</id>
<property name="custName" column="cust_name"></property>
<property name="custLevel" column="cust_level"></property>
<property name="custSource" column="cust_source"></property>
<property name="custIndustry" column="cust_industry"></property>
<property name="custAddress" column="cust_address"></property>
<property name="custPhone" column="cust_phone"></property>
<!-- 一对多关系映射
涉及的标签
set:用于映射set集合属性
属性:
name:指定集合属性的名称
table:在一对多的时候写不写都可以。
它指定的是集合元素所对应的表
one-to-many:用于指定当前映射配置文件所对应的实体和集合元素所对应的实体是一对多关系。
属性:
class:指定集合元素所对应的实体类名称。
key:用于映射外键字段的。
属性:
column:指定从表中的外键字段名称
-->
<set name="linkmans" table="cst_linkman">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
联系人映射文件配置:
<?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 package="com.itheima.domain">
<class name="LinkMan" table="cst_linkman">
<id name="lkmId" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkmName" column="lkm_name"></property>
<property name="lkmGender" column="lkm_gender"></property>
<property name="lkmPhone" column="lkm_phone"></property>
<property name="lkmMobile" column="lkm_mobile"></property>
<property name="lkmEmail" column="lkm_email"></property>
<property name="lkmPosition" column="lkm_position"></property>
<property name="lkmMemo" column="lkm_memo"></property>
<!-- 多对一关系映射
涉及的标签:
many-to-one:用于建立多对一的关系映射配置
属性:
name:指定的实体类中属性的名称
class:该属性所对应的实体类名称。如果在hibernate-mapping上没有导包,则需要写全限定类名
column:指定从表中的外键字段名称
-->
<many-to-one name="customer" class="Customer" column="lkm_cust_id" /> </class>
</hibernate-mapping>
2、多对多关系
此处代码对应的表分别为用户表和角色表,一个用户可以同时拥有多个角色,一个角色可以同时赋予多个用户
用户实体类:
/**
* 用户的数据模型
*/
public class SysUser implements Serializable {
private Long userId;
private String userCode;
private String userName;
private String userPassword;
private String userState;
//多对多关系映射
private Set<SysRole> roles = new HashSet<SysRole>(0);
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserState() {
return userState;
}
public void setUserState(String userState) {
this.userState = userState;
}
public Set<SysRole> getRoles() {
return roles;
}
public void setRoles(Set<SysRole> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
+ userPassword + ", userState=" + userState + "]";
}
}
角色实体类:
/**
* 角色的数据模型
*/
public class SysRole implements Serializable {
private Long roleId;
private String roleName;
private String roleMemo;
//多对多关系映射
private Set<SysUser> users = new HashSet<SysUser>(0);
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleMemo() {
return roleMemo;
}
public void setRoleMemo(String roleMemo) {
this.roleMemo = roleMemo;
}
public Set<SysUser> getUsers() {
return users;
}
public void setUsers(Set<SysUser> users) {
this.users = users;
}
@Override
public String toString() {
return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
}
}
多对多的配置文件:
用户映射关系配置文件:
<?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 package="com.itheima.domain">
<class name="SysUser" table="sys_user">
<id name="userId" column="user_id">
<generator class="native"></generator>
</id>
<property name="userCode" column="user_code"></property>
<property name="userName" column="user_name"></property>
<property name="userPassword" column="user_password"></property>
<property name="userState" column="user_state"></property>
<!-- 多对多关系映射
涉及的标签:
set:用于映射集合属性
属性:
name:指定集合属性的名称
table:指定的是中间表的名称,在多对多的配置时,必须写。
key:指定外键字段
属性:
column:指定的是当前映射文件所对应的实体在中间表的外键字段名称
many-to-many:指定当前映射文件所对应的实体和集合元素所对应的实体是多对多的关系
属性:
class:指定集合元素所对应的实体类
column:指定的是集合元素所对应的实体在中间表的外键字段名称
-->
<set name="roles" table="user_role_rel">
<key column="user_id"></key>
<many-to-many class="SysRole" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
角色配置文件:
<?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 package="com.itheima.domain">
<class name="SysRole" table="sys_role">
<id name="roleId" column="role_id">
<generator class="native"></generator>
</id>
<property name="roleName" column="role_name"></property>
<property name="roleMemo" column="role_memo"></property>
<!-- 多对多关系映射 -->
<set name="users" table="user_role_rel">
<key column="role_id"></key>
<many-to-many class="SysUser" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
3、一对多与多对多的数据保存操作
a、一对多
保存原则:先保存主表,再保存从表
会出现的问题:双向维护了关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样也会修改一次外键。这样就会产生了多余的SQL
解决方法:通过设置inverse="true"来使一方放弃主键的维护,一般一对多中,需要放弃一的一方的外键维护权
<set name="linkmans" table="cst_linkman" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
b、多对多
多对多无保存方向性,但需要注意的是两个实体类对象都要保存,同一对多,也会产生在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
解决方法:任意一方放弃主键的维护权即可:
<set name="users" table="user_role_rel" inverse="true">
<key column="role_id"></key>
<many-to-many class="SysUser" column="user_id"></many-to-many>
</set>
4、级联操作
无论是一对多还是多对多,均存在级联操作
什么是级联操作?
级联操作是指当主控方执行保存、更新或者删除操作时,其关联对象(被控方)也执行相同的操作。在映射文件中通过对cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。
级联操作是有方向性的。
a、级联保存
对于更新操作,一般在一对多的中的一方配置级联保存参数,在多对多中,双方均可。配置格式如下:
在set标签中,设置cascade="save-update"属性
<set name="linkmans" table="cst_linkman" cascade="save-update" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
b、级联删除
级联删除多见于一对多关系中,对于一的一方配置级联删除参数,当删除一的一方时,会自动删除与之关联的多的一方的数据,配置方式为在set标签中配置cascade="delete"属性
set name="linkmans" table="cst_linkman" cascade="delete" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
但是在多对多中,不能使用级联删除, 如果配置了双向级联的话,如果数据之间有相互引用关系,可能会清空所有数据
5、延时加载
session对象中的get和load方法最大的区别就是load方法会进行延迟查询,在一对多多对多中,也可以使用get方式查询,但是配置lazy="true"属性来进行延迟查询配置,该属性可以配置在set标签或者many-to-one标签中