---------------------siwuxie095
Hibernate 多对多操作
以用户和角色为例
(一)多对多映射配置
第一步:创建两个实体类,用户和角色
第二步:让两个实体类之间互相表示
(1)在用户实体类中表示多个角色
(2)在角色实体类中表示多个用户
第三步:配置映射关系
(1)配置基本的映射
(2)配置关联关系的映射(多对多关系)
1)在用户的映射配置文件中,表示所有角色
2)在角色的映射配置文件中,表示所有用户
第四步:在核心配置文件中引入映射配置文件
(二)多对多级联保存
如:添加两个用户,为每个用户添加两个角色
(1)复杂写法
先在角色的映射配置文件中的set 标签添加 inverse 属性,并
将其值设置为true,再进行具体实现
/**
* 多对多级联保存的复杂写法
*
*
* 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 的 jar 包)
*
* 选中方法名,右键->Run As->JUint Test
*/
@Test
publicvoid testSave(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//添加两个用户,为每个用户添加两个角色
//(1)
//创建用户和角色对象
User user1=new User();
user1.setUserName("小白");
user1.setUserPassword("8888");
User user2=new User();
user2.setUserName("小黑");
user2.setUserPassword("4444");
Role role1=new Role();
role1.setRoleName("保镖");
role1.setRoleMemo("强大的保镖");
Role role2=new Role();
role2.setRoleName("秘书");
role2.setRoleMemo("漂亮的秘书");
Role role3=new Role();
role3.setRoleName("司机");
role3.setRoleMemo("称职的司机");
//(2)
//建立用户和角色对象的关系
//
//在用户实体类中表示角色,在角色实体类中表示用户
//
//具体:
//把角色对象放到用户对象的 Set 集合中
//把用户对象放到角色对象的 Set 集合中
//
//user1 --- role1 / role2
//user2 --- role1 / role3
//
//注意:如果建立了双向的关系,一定要有一方放弃外
//键维护权。如下
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
user2.getRoleSet().add(role1);
user2.getRoleSet().add(role3);
role1.getUserSet().add(user1);
role1.getUserSet().add(user2);
role2.getUserSet().add(user1);
role3.getUserSet().add(user2);
//(3)保存到数据库(级联保存)
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
/*
* 由于是多对多且进行了双向关联,所以一定要有一方
* 放弃外键维护权,否则将无法保存到数据库中
*
* 一般由被动方放弃外键维护权,这里角色是被动方
*
* 具体做法:
*
* 在角色的映射配置文件中的 set 标签中添加 inverse
* 属性,并将其值设置为 true
*/
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
(2)简化写法
先在用户的映射配置文件中的set 标签添加 cascade 属性,并
将其值设置为save-update,再进行具体实现
/**
* 多对多级联保存的简化写法
*
* 在用户的映射配置文件中的 set 标签
* 添加 cascade 属性,并将其值设置为
* save-update
*/
@Test
publicvoid testSaveX(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//添加两个用户,为每个用户添加两个角色
//(1)
//创建用户和角色对象
User user1=new User();
user1.setUserName("小白");
user1.setUserPassword("8888");
User user2=new User();
user2.setUserName("小黑");
user2.setUserPassword("4444");
Role role1=new Role();
role1.setRoleName("保镖");
role1.setRoleMemo("强大的保镖");
Role role2=new Role();
role2.setRoleName("秘书");
role2.setRoleMemo("漂亮的秘书");
Role role3=new Role();
role3.setRoleName("司机");
role3.setRoleMemo("称职的司机");
//(2)
//建立用户和角色对象的关系
//
//在用户实体类中表示角色
//
//具体:
//把角色对象放到用户对象的 Set 集合中
//
//user1 --- role1 / role2
//user2 --- role1 / role3
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
user2.getRoleSet().add(role1);
user2.getRoleSet().add(role3);
//(3)保存到数据库(级联保存)
session.save(user1);
session.save(user2);
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
(三)多对多级联删除(一般不使用,仅作了解)
如:删除某个用户
先在用户的映射配置文件中的set 标签添加 cascade 属性,并
将其值设置为delete,再进行具体实现
/**
* 多对多级联删除
*
* 简化写法:在用户的映射配置文件中的 set 标签
* 添加 cascade 属性,并将其值设置为 delete
*/
@Test
publicvoid testDelete(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//(1)
//通过 id 查询用户对象
User user=session.get(User.class, 1);
//(2)
//调用 Session 的 delete() 方法实现级联删除
session.delete(user);
//多对多级联删除,一般不使用,仅作了解即可
//
//注意:此时角色的映射配置文件中的 set 标签
//不能将 inverse 属性设为 true,否则将无法
//删除
//
//另外:set 标签也不能将 cascade 属性设为
//delete,否则 testSaveX() 方法保存的数据
//将全部删除
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
(四)维护第三张表
通过第三张表来维护多对多关系
如:让某个用户有某个角色
第一步:根据id 查询用户和角色
第二步:把角色对象放到用户对象的Set 集合中
再如:让某个用户没有某个角色
第一步:根据id 查询用户和角色
第二步:从用户对象的 Set 集合中移除角色对象
/**
* 维护第三张表
*/
@Test
publicvoid testTable(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//让某个用户有某个角色
//(1)根据 id 查询用户对象和角色对象
User user=session.get(User.class, 1);
Role role=session.get(Role.class, 3);
//(2)把角色对象放到用户对象的 Set 集合中
user.getRoleSet().add(role);
//让某个用户没有某个角色
//(1)根据 id 查询用户对象和角色对象
User userx=session.get(User.class, 1);
Role rolex=session.get(Role.class, 1);
//(2)从用户对象的 Set 集合中移除角色对象
userx.getRoleSet().remove(rolex);
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
工程结构目录如下:
HibernateUtils.java:
package com.siwuxie095.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
static Configuration cfg=null;
static SessionFactory sessionFactory=null;
//或:加上 private final 亦可,不过此时不能等于 null
// private static final Configuration cfg;
// private static final SessionFactory sessionFactory;
//静态代码块
static {
//加载核心配置文件
cfg=new Configuration();
cfg.configure();
sessionFactory=cfg.buildSessionFactory();
}
//提供方法返回 sessionFactory
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
//提供方法返回与本地线程绑定的 Session
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
User.java:
package com.siwuxie095.entity;
import java.util.HashSet;
import java.util.Set;
//用户实体类
public class User {
private Integer uid; //用户 id
private String userName; //用户名称
private String userPassword; //用户密码
//在用户实体类中表示多个角色,即一个用户可以有多个角色
//
//Hibernate 中要求使用 Set 集合表示"多"的数据
private Set<Role> roleSet=new HashSet<Role>();
public Set<Role> getRoleSet() {
return roleSet;
}
publicvoid setRoleSet(Set<Role> roleSet) {
this.roleSet = roleSet;
}
public Integer getUid() {
return uid;
}
publicvoid setUid(Integer uid) {
this.uid = uid;
}
public String getUserName() {
return userName;
}
publicvoid setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
publicvoid setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
Role.java:
package com.siwuxie095.entity;
import java.util.HashSet;
import java.util.Set;
//角色实体类
public class Role {
private Integer rid; //角色 id
private String roleName; //角色名称
private String roleMemo; //角色描述
//在角色实体类中表示多个用户,即一个角色可以有多个用户
//
//Hibernate 中要求使用 Set 集合表示"多"的数据
private Set<User> userSet=new HashSet<User>();
public Set<User> getUserSet() {
return userSet;
}
publicvoid setUserSet(Set<User> userSet) {
this.userSet = userSet;
}
public Integer getRid() {
return rid;
}
publicvoid setRid(Integer rid) {
this.rid = rid;
}
public String getRoleName() {
return roleName;
}
publicvoid setRoleName(String roleName) {
this.roleName = roleName;
}
public String getRoleMemo() {
return roleMemo;
}
publicvoid setRoleMemo(String roleMemo) {
this.roleMemo = roleMemo;
}
}
HibernateManyToMany.java:
package com.siwuxie095.hibernatetest;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.Test;
import com.siwuxie095.entity.Role;
import com.siwuxie095.entity.User;
import com.siwuxie095.utils.HibernateUtils;
//多对多操作
public class HibernateManyToMany {
/**
* 多对多级联保存的复杂写法
*
*
* 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 的 jar 包)
*
* 选中方法名,右键->Run As->JUint Test
*/
@Test
publicvoid testSave(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//添加两个用户,为每个用户添加两个角色
//(1)
//创建用户和角色对象
User user1=new User();
user1.setUserName("小白");
user1.setUserPassword("8888");
User user2=new User();
user2.setUserName("小黑");
user2.setUserPassword("4444");
Role role1=new Role();
role1.setRoleName("保镖");
role1.setRoleMemo("强大的保镖");
Role role2=new Role();
role2.setRoleName("秘书");
role2.setRoleMemo("漂亮的秘书");
Role role3=new Role();
role3.setRoleName("司机");
role3.setRoleMemo("称职的司机");
//(2)
//建立用户和角色对象的关系
//
//在用户实体类中表示角色,在角色实体类中表示用户
//
//具体:
//把角色对象放到用户对象的 Set 集合中
//把用户对象放到角色对象的 Set 集合中
//
//user1 --- role1 / role2
//user2 --- role1 / role3
//
//注意:如果建立了双向的关系,一定要有一方放弃外
//键维护权。如下
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
user2.getRoleSet().add(role1);
user2.getRoleSet().add(role3);
role1.getUserSet().add(user1);
role1.getUserSet().add(user2);
role2.getUserSet().add(user1);
role3.getUserSet().add(user2);
//(3)保存到数据库(级联保存)
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
/*
* 由于是多对多且进行了双向关联,所以一定要有一方
* 放弃外键维护权,否则将无法保存到数据库中
*
* 一般由被动方放弃外键维护权,这里角色是被动方
*
* 具体做法:
*
* 在角色的映射配置文件中的 set 标签中添加 inverse
* 属性,并将其值设置为 true
*/
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
/**
* 多对多级联保存的简化写法
*
* 在用户的映射配置文件中的 set 标签
* 添加 cascade 属性,并将其值设置为
* save-update
*/
@Test
publicvoid testSaveX(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//添加两个用户,为每个用户添加两个角色
//(1)
//创建用户和角色对象
User user1=new User();
user1.setUserName("小白");
user1.setUserPassword("8888");
User user2=new User();
user2.setUserName("小黑");
user2.setUserPassword("4444");
Role role1=new Role();
role1.setRoleName("保镖");
role1.setRoleMemo("强大的保镖");
Role role2=new Role();
role2.setRoleName("秘书");
role2.setRoleMemo("漂亮的秘书");
Role role3=new Role();
role3.setRoleName("司机");
role3.setRoleMemo("称职的司机");
//(2)
//建立用户和角色对象的关系
//
//在用户实体类中表示角色
//
//具体:
//把角色对象放到用户对象的 Set 集合中
//
//user1 --- role1 / role2
//user2 --- role1 / role3
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
user2.getRoleSet().add(role1);
user2.getRoleSet().add(role3);
//(3)保存到数据库(级联保存)
session.save(user1);
session.save(user2);
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
/**
* 多对多级联删除
*
* 简化写法:在用户的映射配置文件中的 set 标签
* 添加 cascade 属性,并将其值设置为 delete
*/
@Test
publicvoid testDelete(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//(1)
//通过 id 查询用户对象
User user=session.get(User.class, 1);
//(2)
//调用 Session 的 delete() 方法实现级联删除
session.delete(user);
//多对多级联删除,一般不使用,仅作了解即可
//
//注意:此时角色的映射配置文件中的 set 标签
//不能将 inverse 属性设为 true,否则将无法
//删除
//
//另外:set 标签也不能将 cascade 属性设为
//delete,否则 testSaveX() 方法保存的数据
//将全部删除
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
/**
* 维护第三张表
*/
@Test
publicvoid testTable(){
SessionFactory sessionFactory=null;
Session session=null;
Transaction tx=null;
try {
//得到 SessionFactory 对象
sessionFactory=HibernateUtils.getSessionFactory();
//创建 Session 对象
session=sessionFactory.openSession();
//开启事务
tx=session.beginTransaction();
//让某个用户有某个角色
//(1)根据 id 查询用户对象和角色对象
User user=session.get(User.class, 1);
Role role=session.get(Role.class, 3);
//(2)把角色对象放到用户对象的 Set 集合中
user.getRoleSet().add(role);
//让某个用户没有某个角色
//(1)根据 id 查询用户对象和角色对象
User userx=session.get(User.class, 1);
Role rolex=session.get(Role.class, 1);
//(2)从用户对象的 Set 集合中移除角色对象
userx.getRoleSet().remove(rolex);
//提交事务
tx.commit();
} catch (Exception e) {
//回滚事务
tx.rollback();
} finally {
//关闭资源
session.close();
sessionFactory.close();
}
}
}
User.hbm.xml:
<?xmlversion="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>
<!--
(1)
class 标签:配置实体类和数据库表的对应;
name 属性:实体类的全路径,即全限定名;
table 属性:数据库表的名称(数据库表由 Hibernate 自动生成)
-->
<classname="com.siwuxie095.entity.User"table="t_user">
<!--
(2)
id 标签:配置实体类 id 和表 id 对应(主键);
name 属性:实体类里 id 属性名称;
column 属性:生成表中 id 字段名称
-->
<idname="uid"column="uid">
<generatorclass="native"></generator>
</id>
<!--
(3)
property 标签:配置其它属性和表中字段对应;
name 属性:实体类属性名称;
column 属性:生成表中字段名称
-->
<propertyname="userName"column="user_name"></property>
<propertyname="userPassword"column="user_password"></property>
<!--
(4)
set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合;
name 属性:关联另一方的对象的 Set 集合的名称(在用户实体类中声明);
table 属性:第三张表的名称;
cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开);
inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false)
-->
<setname="roleSet"table="user_role"cascade="delete">
<!--
key 标签:配置当前对象(关联一方)在第三张表中的外键
column 属性:当前对象(关联一方)在第三张表中的外键名称
-->
<keycolumn="user_id"></key>
<!--
many-to-many 标签:配置实体类的多对多关联;
class:关联另一方的类的全路径,即角色实体类的全限定名;
column:关联的另一方在第三张表的外键名称,即角色表在第三张表中的外键名称
-->
<many-to-manyclass="com.siwuxie095.entity.Role"column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
Role.hbm.xml:
<?xmlversion="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>
<classname="com.siwuxie095.entity.Role"table="t_role">
<idname="rid"column="rid">
<generatorclass="native"></generator>
</id>
<propertyname="roleName"column="role_name"></property>
<propertyname="roleMemo"column="role_memo"></property>
<!--
set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合;
name 属性:关联另一方的对象的 Set 集合的名称(在角色实体类中声明);
table 属性:第三张表的名称;
cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开);
inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false)
-->
<setname="userSet"table="user_role"cascade="save-update"inverse="false">
<!--
key 标签:配置当前对象(关联一方)在第三张表中的外键
column 属性:当前对象(关联一方)在第三张表中的外键名称
-->
<keycolumn="role_id"></key>
<!--
many-to-many 标签:配置实体类的多对多关联;
class:关联另一方的类的全路径,即用户实体类的全限定名;
column:关联的另一方在第三张表的外键名称,即用户表在第三张表中的外键名称
-->
<many-to-manyclass="com.siwuxie095.entity.User"column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml:
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 第一部分:配置数据库信息(必须) -->
<propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 或使用 jdbc:mysql:///hibernate_db 代替,省略 localhost:3306 -->
<propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property>
<propertyname="hibernate.connection.username">root</property>
<propertyname="hibernate.connection.password">8888</property>
<!-- 第二部分:配置 Hibernate 信息(可选) -->
<!-- 输出底层 sql 语句 -->
<propertyname="hibernate.show_sql">true</property>
<!-- 输出底层 sql 语句格式 -->
<propertyname="hibernate.format_sql">true</property>
<!--
Hibernate 帮助创建表,不是自动创建,而需要配置之后。
update:如果已经有表,就更新,如果没有,就自动创建
-->
<propertyname="hibernate.hbm2ddl.auto">update</property>
<!--
配置数据库方言,让 Hibernate 框架识别不同数据库自己特有的语句
如:在 MySQL 中实现分页的关键字 limit,只能在 MySQL 中使用,而
在 Oracle 中实现分页的关键字则是 rownum
-->
<propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 配置 Session 绑定本地线程 -->
<propertyname="hibernate.current_session_context_class">thread</property>
<!-- 第三部分:引入映射配置文件,把映射配置文件放到核心配置文件(必须) -->
<mappingresource="com/siwuxie095/entity/User.hbm.xml"/>
<mappingresource="com/siwuxie095/entity/Role.hbm.xml"/>
</session-factory>
</hibernate-configuration>
【made by siwuxie095】
