一、表关系的分析
数据库中多表之间存在着三种关系,也就是系统设计中的三种实体关系。如图所示。
的关系,在A类中定义B类类型的Set集合,在B类中定义A类类型的Set集合,这里用Set集合
联系人表中存在外键(lkm_cust_id),外键指向客户表,表示如下图:
2.2 创建实体:
客户实体:
package com.Kevin.domain;
/**
* 创建客户实体类
*
*/ import java.io.Serializable;
import java.util.HashSet;
import java.util.Set; public class Customer implements Serializable {
private Long cust_id;
private String cust_name;
private String cust_address;
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<Linkman>(0); //一对多关系映射:多的一方
//主表实体应该包含从表实体的集合引用
public Set<Linkman> getLinkmans() {
return linkmans;
}
public void setLinkmans(Set<Linkman> linkmans) {
this.linkmans = linkmans;
}
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_address() {
return cust_address;
}
public void setCust_address(String cust_address) {
this.cust_address = cust_address;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_address=" + cust_address + ", cust_name=" + cust_name
+ ", cust_source=" + cust_source + ", cust_industry=" + cust_industry + ", cust_level=" + cust_level
+ ", cust_phone=" + cust_phone + ", cust_mobile=" + cust_mobile + "]";
} }
联系人实体:
package com.Kevin.domain;
/**
* 创建联系人实体类
*
*/
import java.io.Serializable; public class Linkman implements Serializable {
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_mobile;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo; //一对多关系影射
//从表实体包含主表实体的对象引用
private Customer customer; public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Long getLkm_id() {
return lkm_id;
}
public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_mobile() {
return lkm_mobile;
}
public void setLkm_mobile(String lkm_mobile) {
this.lkm_mobile = lkm_mobile;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
public String getLkm_email() {
return lkm_email;
}
public void setLkm_email(String lkm_email) {
this.lkm_email = lkm_email;
}
public String getLkm_qq() {
return lkm_qq;
}
public void setLkm_qq(String lkm_qq) {
this.lkm_qq = lkm_qq;
}
public String getLkm_position() {
return lkm_position;
}
public void setLkm_position(String lkm_position) {
this.lkm_position = lkm_position;
}
public String getLkm_memo() {
return lkm_memo;
}
public void setLkm_memo(String lkm_memo) {
this.lkm_memo = lkm_memo;
}
@Override
public String toString() {
return "Linkman [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + ", lkm_gender=" + lkm_gender + ", lkm_mobile="
+ lkm_mobile + ", lkm_phone=" + lkm_phone + ", lkm_email=" + lkm_email + ", lkm_qq=" + lkm_qq
+ ", lkm_position=" + lkm_position + ", lkm_memo=" + lkm_memo + "]";
} }
2.3 创建映射
客户映射:
<?xml version="1.0" encoding="UTF-8"?>
<!--
创建客户类关系映射
导入dtd约束
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
private Long cust_id;
private String cust_address;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
-->
<hibernate-mapping package="com.Kevin.domain">
<class name="Customer" table="cust_customer" lazy="false">
<id name="cust_id">
<generator class="native"></generator>
</id>
<property name="cust_name" column="cust_name"></property>
<property name="cust_address" column="cust_address"></property>
<property name="cust_source" column="cust_source"></property>
<property name="cust_industry" column="cust_industry"></property>
<property name="cust_level" column="cust_level"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property> <!-- 一对多关系影射:主表实体的映射配置
涉及的标签:set:用于配置set集合属性
属性:name:指定实体类中set集合的属性名称
table:指定从表的名称,在一对多配置时可以不写
key:用于映射外键字段
属性:column:指定外键字段名称
one—to—many:用于建立一对多的映射配置
属性:class:指定从表实体类的名称
-->
<set name="linkmans" table="cust_linkman" >
<key column="lkm_cust_id"></key>
<one-to-many class="Linkman"/>
</set>
</class>
</hibernate-mapping>
联系人映射:
<?xml version="1.0" encoding="UTF-8"?>
<!--
创建联系人实体类映射
导入dtd约束
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_mobile;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
-->
<hibernate-mapping package="com.Kevin.domain">
<class name="Linkman" table="cust_linkman">
<id name="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<property name="lkm_memo" column="lkm_memo"></property> <!-- 一对多关系影射:从表实体的映射配置
涉及的标签:many-to-one:建立多对一的映射配置
属性:name:从表示实体中引用主表实体对象的引用的名称
class:指定属性所对应的实体类名称
-->
<many-to-one name="customer" class="Customer" column="lkm_cust_id" ></many-to-one>
</class>
</hibernate-mapping>
customer在 Linkman.java类中的属性的名称,class属性用来指定映射的类,column属性值对应表中的外键列名。
<mapping resource="com/Kevin/domain/Linkman.hbm.xml"/>
<mapping resource="com/Kevin/domain/Customer.hbm.xml"/>
2.5 编写测试代码
@Test
public void test2(){
Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); //1.创建一个客户
Customer c1=new Customer(); //瞬时态
c1.setCust_name("Kevin_one2many");
//2.创建一个新的联系人
Linkman lkm1=new Linkman(); //瞬时态
lkm1.setLkm_name("Kevin_one2many1");
Linkman lkm2=new Linkman(); //瞬时态
lkm2.setLkm_name("Kevin_one2many2");
//3.建立客户和联系人的关联关系(让双向)
lkm1.setCustomer(c1);
lkm2.setCustomer(c1);
c1.getLinkmans().add(lkm1);
c1.getLinkmans().add(lkm2);
//4.保存要符合原则
s.save(c1); //持久态 有一级缓存和快照
s.save(lkm1); //持久态 有一级缓存和快照
s.save(lkm2);
tx.commit();
}
在配置文件中添加了自动建表信息后,运行程序时,程序会自动创建两张表,并且插入数据。运行方法后,控制台输出结果如所示:
从图的输出结果可以看到,控制台成功输出了三条insert语句和两条update语句,此时查询数据库中的数据如图所示:
从上图的查询结果可以看出,数据表创建成功,并成功插入了相应的数据。那么一个基本的一对多的关联关系映射就已经配置好了。从以上代码我们可以发现我们建立的关系是双向的,即客户关联了联系人,同时联系人也关联了客户。
三、一对多的相关操作
级联操作是指当主控方执行保存、更新或者删除操作时,其关联对象(被控方)也执行相同的操作。在映射文件中通过对 cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。
3.1 级联保存或更新
首先要确定我们要保存的主控方是那一方,我们要保存客户,所以客户是主控方,那么需要在客户的映射文件中进行如下的配置。
<!-- 一对多关系影射:主表实体的映射配置
涉及的标签:set:用于配置set集合属性
属性:name:指定实体类中set集合的属性名称
table:指定从表的名称,在一对多配置时可以不写
key:用于映射外键字段
属性:column:指定外键字段名称
one—to—many:用于建立一对多的映射配置
属性:class:指定从表实体类的名称 -->
<set name="linkmans" table="cust_linkman" cascade="save-update">
<key column="lkm_cust_id"></key>
<one-to-many class="Linkman"/>
</set>
然后可以编写如下测试代码:
@Test
public void test(){
Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); //1.创建一个客户
Customer c1=new Customer(); //瞬时态
c1.setCust_name("Kevin");
//2.创建一个新的联系人
Linkman lkm1=new Linkman(); //瞬时态
lkm1.setLkm_name("Kevin_one2many");
//3.建立客户和联系人的关联关系(让双向)
lkm1.setCustomer(c1);
c1.getLinkmans().add(lkm1);
//4.保存要符合原则
s.save(c1); //持久态 有一级缓存和快照
tx.commit();
}
保存联系人级联客户
同样我们需要确定主控方,现在我们的主控方是联系人。所以需要在联系人的映射文件中进行配置,内容如下:
<!-- 一对多关系影射:从表实体的映射配置
涉及的标签:many-to-one:建立多对一的映射配置
属性:name:从表示实体中引用主表实体对象的引用的名称
class:指定属性所对应的实体类名称
-->
<many-to-one name="customer" class="Customer" column="lkm_cust_id" cascade="save-update"></many-to-one>
编写如下测试代码:
@Test
public void test(){
Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); //1.创建一个客户
Customer c1=new Customer(); //瞬时态
c1.setCust_name("Kevin");
//2.创建一个新的联系人
Linkman lkm1=new Linkman(); //瞬时态
lkm1.setLkm_name("Kevin_one2many");
//3.建立客户和联系人的关联关系(让双向)
lkm1.setCustomer(c1);
c1.getLinkmans().add(lkm1);
//4.保存要符合原则
s.save(lkm1); //持久态 有一级缓存和快照
tx.commit();
}
3.2 级联更新
@Test
public void test5(){
Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); //1.查询一个客户
Customer c1=s.get(Customer.class, 1l);
//2.创建一个新的联系人
Linkman lkm=new Linkman(); //瞬时态
lkm.setLkm_name("one2many_update");
//3.建立客户和联系人的关联关系(双向)
lkm.setCustomer(c1);
c1.getLinkmans().add(lkm);
//4.更新联系人
s.update(c1);
tx.commit();
}
3.3 Hibernate 的级联删除
@Test
public void test6(){
Session s=HibernateUtil.getCurrSession();
Transaction tx =s.beginTransaction(); Customer c=s.get(Customer.class, 71);
//删除客户
s.delete(c);
tx.commit();
}
确定删除的主控方式客户,所以需要在客户端配置:
<set name="linkmans" table="cust_linkman" cascade="save-update,delete">
<key column="lkm_cust_id"></key>
<one-to-many class="Linkman"/>
</set>
编写如下测试代码:
@Test
public void test6(){
Session s=HibernateUtil.getCurrSession();
Transaction tx =s.beginTransaction(); Customer c=s.get(Customer.class, 7l);
//删除客户
s.delete(c);
tx.commit();
}
inverse的默认值是false ,代表不放弃外键维护权,配置值为true,代表放弃了外键的维护权。此时就不会再产生之前的问题。
四、Hibernate的多对多关联关系映射
4.1 创建表
数据模型如下:
4.2 创建实体
用户实体:
package com.Kevin.domain;
/**
* 用户实体类
*/ import java.io.Serializable;
import java.util.HashSet;
import java.util.Set; public class SysUser implements Serializable {
private Long userId;
private String userName;
private String userPassword;
private Integer userState;
//多对多关系映射:
private Set<SysRole> roles=new HashSet<SysRole>(0); public Set<SysRole> getRoles() {
return roles;
}
public void setRoles(Set<SysRole> roles) {
this.roles = roles;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
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 Integer getUserState() {
return userState;
}
public void setUserState(Integer userState) {
this.userState = userState;
}
@Override
public String toString() {
return "SysUser [userId=" + userId + ", userName=" + userName + ", userPassword=" + userPassword
+ ", userState=" + userState + "]";
} }
角色实体:
package com.Kevin.domain;
/**
* 角色的实体类
*/ import java.io.Serializable;
import java.util.HashSet;
import java.util.Set; public class SysRole implements Serializable {
private Long roleId;
private String roleName;
private String roleMemo;
//多对多关系映射:一个角色可以赋予多个用户
private Set<SysUser> users=new HashSet<SysUser>(0); public Set<SysUser> getUsers() {
return users;
}
public void setUsers(Set<SysUser> users) {
this.users = users;
}
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;
}
@Override
public String toString() {
return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
} }
4.3 创建映射
用户映射:
<?xml version="1.0" encoding="UTF-8"?>
<!--
创建用户类关系映射
导入dtd约束
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
private Long userId;
private String userName;
private String userPassword;
private Integer userState;
-->
<hibernate-mapping package="com.Kevin.domain">
<class name="SysUser" table="sys_user" >
<id name="userId" column="user_id">
<generator class="native"></generator>
</id>
<property name="userName" column="user_name"></property>
<property name="userPassword" column="user_password"></property>
<property name="userState" column="user_state"></property>
<!--
多对多关系映射涉及的标签:
set:用于映射set集合属性
name:指定集合名称
table:指定中间表的名称
key:用于映射外键字段
column:指定当前实体在中间表的外键字段名称
many-to-many:用于映射多对多的关系
class:对方的实体类
column: 对方在中间类的外键字段名称
-->
<set name="roles" table="user_role_ref" inverse="true" cascade="delete">
<key column="user_id"></key>
<many-to-many class="SysRole" column="role_id" />
</set>
</class>
</hibernate-mapping>
角色映射:
<?xml version="1.0" encoding="UTF-8"?>
<!--
创建用户类关系映射
导入dtd约束
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!--
private Long roleId;
private String roleName;
private String roleMemo;
-->
<hibernate-mapping package="com.Kevin.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:用于映射set集合属性
name:指定集合名称
table:指定中间表的名称
key:用于映射外键字段
column:指定当前实体在中间表的外键字段名称
many-to-many:用于映射多对多的关系
class:对方的实体类
column: 对方在中间类的外键字段名称
-->
<set name="users" table="user_role_ref" cascade="delete">
<key column="role_id"></key>
<many-to-many class="SysUser" column="user_id"/>
</set>
</class>
</hibernate-mapping>
4.4 在核心配置中加入映射文件
<mapping resource="com/Kevin/domain/SysUser.hbm.xml"/>
<mapping resource="com/Kevin/domain/SysRole.hbm.xml"/>
4.5 编写测试类
/**
* 保存操作:需求:创建2个用户和3个角色
* 让1号用户具备1号和2号角色
* 让2号用户具备2号和3号角色
* 保存用户和角色
*/
@Test
public void test(){
SysUser u1=new SysUser();
u1.setUserName("User1");
SysUser u2=new SysUser();
u2.setUserName("User2"); SysRole r1=new SysRole();
r1.setRoleName("Role1");
SysRole r2=new SysRole();
r2.setRoleName("Role2");
SysRole r3=new SysRole();
r3.setRoleName("Role3"); //建立双相关联关系
//先建立用户
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r2);
u2.getRoles().add(r3);
//建立角色
r1.getUsers().add(u1);
r2.getUsers().add(u1);
r2.getUsers().add(u2);
r3.getUsers().add(u2); Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); s.save(u1);
s.save(u2);
s.save(r1);
s.save(r2);
s.save(r3);
tx.commit();
}
五、多对多的相关操作
5.1 级联保存或更新
之前已经学习过一对多的级联保存了,那么多对多也是一样的。如果只保存单独的一方是不可以的,还是需要保存双方的。如果就想保存一方就需要设置级联操作。同样要看保存的主控方是哪一端,就需要在那一端进行配置。
保存用户级联角色
编写测试代码:
/**
* 级联保存操作:
* 需求:创建2个用户和3个角色
* 让1号用户具备1号和2号角色
* 让2号用户具备2号和3号角色
* 保存用户和角色
*/
@Test
public void test1(){
SysUser u1=new SysUser();
u1.setUserName("User1");
SysUser u2=new SysUser();
u2.setUserName("User2"); SysRole r1=new SysRole();
r1.setRoleName("Role1");
SysRole r2=new SysRole();
r2.setRoleName("Role2");
SysRole r3=new SysRole();
r3.setRoleName("Role3"); //建立双相关联关系
//先建立用户
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r2);
u2.getRoles().add(r3);
//建立角色
r1.getUsers().add(u1);
r2.getUsers().add(u1);
r2.getUsers().add(u2);
r3.getUsers().add(u2); Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); s.save(u1);
s.save(u2);
tx.commit();
}
保存角色级联用户
编写测试代码:
/**
* 级联保存操作:保存角色级联用户
* 需求:创建2个用户和3个角色
* 让1号用户具备1号和2号角色
* 让2号用户具备2号和3号角色
* 保存用户和角色
*/
@Test
public void test3(){
SysUser u1=new SysUser();
u1.setUserName("User1");
SysUser u2=new SysUser();
u2.setUserName("User2"); SysRole r1=new SysRole();
r1.setRoleName("Role1");
SysRole r2=new SysRole();
r2.setRoleName("Role2");
SysRole r3=new SysRole();
r3.setRoleName("Role3"); //建立双相关联关系
//先建立用户
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r2);
u2.getRoles().add(r3);
//建立角色
r1.getUsers().add(u1);
r2.getUsers().add(u1);
r2.getUsers().add(u2);
r3.getUsers().add(u2); Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction();
s.save(r1);
s.save(r2);
s.save(r3);
tx.commit();
}
5.2 级联删除(了解)
级联删除仅作了解,因为在实际开发中是禁止用的。由于在多对多关联关系下,往往有多个对象是关联的,因此只要删除一个,使用级联操作,就会删除多个对象和数据。
测试代码:
/**
* 删除操作
* 在实际开发中:多对多的双向级联删除是禁止使用的
*/
@Test
public void test2(){
Session s=HibernateUtil.getCurrSession();
Transaction tx=s.beginTransaction(); SysUser u1=s.get(SysUser.class, 1l); s.delete(u1);
tx.commit();
}
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3gy4lgwd4jqc4