多对多关系以介绍
上一节讨论了Hibernate一对多关系的维护,这节讨论多对多关系的维护
在实际生活中,有很多多对多的例子:
比如老师和学生的关系.职员和职位的关系..等等.
由于多对多关系中不能在两个关系表中插入对应的主键作为外键,所以要新建一张表来维护两者的关系
我用支援和职位的背景作为Demo实例
数据库表与实体表的模型图
用户表的对应关系
角色表的对应关系
配置实体映射的文件
User的实体表
package com.tangbaobao.domain;
import java.util.HashSet;
import java.util.Set;
/**
* @author 唐学俊
* @version 创建时间:2017年11月22日 下午1:56:49
*
*/
public class User {
/*CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) NOT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) NOT NULL COMMENT '用户密码',
`user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;*/
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private Character user_state;
private Set<Role> roles = new HashSet<Role>();
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
public String getUser_code() {
return user_code;
}
public void setUser_code(String user_code) {
this.user_code = user_code;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getUser_password() {
return user_password;
}
public void setUser_password(String user_password) {
this.user_password = user_password;
}
public Character getUser_state() {
return user_state;
}
public void setUser_state(Character user_state) {
this.user_state = user_state;
}
@Override
public String toString() {
return "User [user_id=" + user_id + ", user_code=" + user_code + ", user_name=" + user_name + ", user_password="
+ user_password + ", user_state=" + user_state + "]";
}
}
1.User.hbm.xml
<?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.tangbaobao.domain">
<class name="User" table="sys_user">
<id name ="user_id">
<generator class="native"></generator>
</id>
<property name="user_code"></property>
<property name="user_name"></property>
<property name="user_password"></property>
<property name="user_state"></property>
<!--
name:集合属性名
table:配置中间表名
key
column:外键:别人引用我
class:我与那个类是多对多关系
Many
column:我引用别人的主键
-->
<!-- 多对多关系 -->
<set name="roles" table ="sys_user_role">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
Role的实体表
package com.tangbaobao.domain;
/**
* @author 唐学俊
* @version 创建时间:2017年11月22日 下午2:02:21
*
*/
import java.util.HashSet;
import java.util.Set;
public class Role {
/* CREATE TABLE `sys_role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;*/
private Long role_id;
private String role_name;
private String role_memo;
private Set<User> users = new HashSet<User>();
public Long getRole_id() {
return role_id;
}
public void setRole_id(Long role_id) {
this.role_id = role_id;
}
public String getRole_name() {
return role_name;
}
public void setRole_name(String role_name) {
this.role_name = role_name;
}
public String getRole_memo() {
return role_memo;
}
public void setRole_memo(String role_memo) {
this.role_memo = role_memo;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
}
2.配置Role.hbm.xml
<?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.tangbaobao.domain">
<class name="Role" table="sys_role">
<id name ="role_id">
<generator class="native"></generator>
</id>
<property name="role_name"></property>
<property name="role_memo"></property>
<set name="users" table="sys_user_role" >
<key column="role_id"></key><!-- 别人引用我的 -->
<many-to-many class="User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
对多对多关系进行操作
package com.tangbaobao.test;
/**
* @author 唐学俊
* @version 创建时间:2017年11月22日 下午6:20:58
*
*/
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.tangbaobao.domain.Role;
import com.tangbaobao.domain.User;
import com.tangbaobao.utils.HibernateUtils;
public class Test4 {
@Test
public void fun1() {
//获得session
Session session = HibernateUtils.getSession();
//开始事务
Transaction tx = session.beginTransaction();
// ----------------------------------------------
//操作
//1.创建两个User
User user1 = new User();
user1.setUser_name("唐学俊");
User user2 = new User();
user2.setUser_name("唐丽");
//2创建两个Role
Role role1 = new Role();
role1.setRole_name("学生");
Role role2 = new Role();
role2.setRole_name("老师");
//3用户表达关系
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role1);
user2.getRoles().add(role2);
//4角色表达关系
role1.getUsers().add(user1);
role1.getUsers().add(user2);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
//5调用save方法保存
session.save(role2);
session.save(role1);
session.save(user1);
session.save(user2);
// ----------------------------------------------
//提交事务
tx.commit();
}
//为用户增加角色
@Test
public void fun2() {
//获得session
Session session = HibernateUtils.getSession();
//开始事务
Transaction tx = session.beginTransaction();
// ----------------------------------------------
//操作
//1.获得唐学俊角色
User user = session.get(User.class, 1L);
//2创建一个角色
Role role = new Role();
role.setRole_name("CEO");
//3将角色绑定用户
user.getRoles().add(role);
//4将角色转换为持久状态
session.save(role);
// ----------------------------------------------
//提交事务
tx.commit();
}
//为用户解除角色
@Test
public void fun3() {
//获得session
Session session = HibernateUtils.getSession();
//开始事务
Transaction tx = session.beginTransaction();
// ----------------------------------------------
//操作
//1.获得唐学俊
User user = session.get(User.class, 1L);
//2.获取角色
Role role = session.get(Role.class, 2L);
//3.将角色从用户中移除
user.getRoles().remove(role);
// ----------------------------------------------
//提交事务
tx.commit();
}
}
存在问题
多对多关系中,由第三张表维护其中的关系,如果在配置其对应关系时都配置,则会出现主键重复
像这样
解决办法就是其中的一方放弃维护主键,这里有两种解决办法
1.在java程序取消设置一方的关系
2.在一方的xml文件中配置属性inverse,放弃维护主键
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id"></key><!-- 别人引用我的 -->
<many-to-many class="User" column="user_id"></many-to-many>
</set>
用cascade简化操作
casecade是设置级联属性操作,可以在对象持久化到数据库库中简化操作
比如在上面的示例可以写成这样
在Role.hbm.xml中设置role的级联属性
<set name="users" table="sys_user_role" inverse="true" cascade="save-update">
<key column="role_id"></key><!-- 别人引用我的 -->
<many-to-many class="User" column="user_id"></many-to-many>
</set>
java程序中的变化
//5调用save方法保存
session.save(role2);
session.save(role1);
//session.save(user1);
//session.save(user2);
总结
学习hibernate多表操作可以将两种关系归类总结为以下
- 确定业务表
- 新建实体表
- 配置实体表映射文件,并将配置信息加入到主配置文件中
- 根据需求配置inverse属性
- 根据需求配置cascade属性简化操作