---------------------siwuxie095
Hibernate 多对多操作
以用户和角色为例
(一)多对多映射配置
第一步:创建两个实体类,用户和角色
第二步:让两个实体类之间互相表示
(1)在用户实体类中表示多个角色
(2)在角色实体类中表示多个用户
第三步:配置映射关系
(1)配置基本的映射
(2)配置关联关系的映射(多对多关系)
1)在用户的映射配置文件中,表示所有角色
2)在角色的映射配置文件中,表示所有用户
第四步:在核心配置文件中引入映射配置文件
(二)多对多级联保存
如:添加两个用户,为每个用户添加两个角色
(1)复杂写法
先在角色的映射配置文件中的 set 标签添加 inverse 属性,并
将其值设置为 true,再进行具体实现
/** * 多对多级联保存的复杂写法 * * * 手动加上 @Test 以进行单元测试(将自动导入 JUnit 4 的 jar 包) * * 选中方法名,右键->Run As->JUint Test */ @Test public void 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 public void 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 public void 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 public void 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; } public void setRoleSet(Set<Role> roleSet) { this.roleSet = roleSet; } public Integer getUid() { return uid; } public void setUid(Integer uid) { this.uid = uid; } 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; } } |
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; } public void setUserSet(Set<User> userSet) { this.userSet = userSet; } public Integer getRid() { return rid; } public void setRid(Integer rid) { this.rid = rid; } 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; } } |
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 public void 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 public void 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 public void 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 public void 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:
<?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>
<!-- (1) class 标签:配置实体类和数据库表的对应; name 属性:实体类的全路径,即全限定名; table 属性:数据库表的名称(数据库表由 Hibernate 自动生成) --> <class name="com.siwuxie095.entity.User" table="t_user"> <!-- (2) id 标签:配置实体类 id 和表 id 对应(主键); name 属性:实体类里 id 属性名称; column 属性:生成表中 id 字段名称 --> <id name="uid" column="uid"> <generator class="native"></generator> </id> <!-- (3) property 标签:配置其它属性和表中字段对应; name 属性:实体类属性名称; column 属性:生成表中字段名称 --> <property name="userName" column="user_name"></property> <property name="userPassword" column="user_password"></property> <!-- (4) set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合; name 属性:关联另一方的对象的 Set 集合的名称(在用户实体类中声明); table 属性:第三张表的名称; cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开); inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false) --> <set name="roleSet" table="user_role" cascade="delete"> <!-- key 标签:配置当前对象(关联一方)在第三张表中的外键 column 属性:当前对象(关联一方)在第三张表中的外键名称 --> <key column="user_id"></key> <!-- many-to-many 标签:配置实体类的多对多关联; class:关联另一方的类的全路径,即角色实体类的全限定名; column:关联的另一方在第三张表的外键名称,即角色表在第三张表中的外键名称 --> <many-to-many class="com.siwuxie095.entity.Role" column="role_id"></many-to-many> </set> </class> </hibernate-mapping> |
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>
<class name="com.siwuxie095.entity.Role" table="t_role"> <id name="rid" column="rid"> <generator class="native"></generator> </id> <property name="roleName" column="role_name"></property> <property name="roleMemo" column="role_memo"></property> <!-- set 标签:配置关联关系的映射(配置关联对象),代表一个 Set 集合; name 属性:关联另一方的对象的 Set 集合的名称(在角色实体类中声明); table 属性:第三张表的名称; cascade 属性:save-update 表示级联保存,delete 表示级联删除(逗号隔开); inverse 属性:true 表示放弃关系维护(放弃外键的维护权)(默认为 false) --> <set name="userSet" table="user_role" cascade="save-update" inverse="false"> <!-- key 标签:配置当前对象(关联一方)在第三张表中的外键 column 属性:当前对象(关联一方)在第三张表中的外键名称 --> <key column="role_id"></key> <!-- many-to-many 标签:配置实体类的多对多关联; class:关联另一方的类的全路径,即用户实体类的全限定名; column:关联的另一方在第三张表的外键名称,即用户表在第三张表中的外键名称 --> <many-to-many class="com.siwuxie095.entity.User" column="user_id"></many-to-many> </set> </class> </hibernate-mapping> |
hibernate.cfg.xml:
<?xml version="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> <!-- 第一部分:配置数据库信息(必须) --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- 或使用 jdbc:mysql:///hibernate_db 代替,省略 localhost:3306 --> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_db</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">8888</property> <!-- 第二部分:配置 Hibernate 信息(可选) --> <!-- 输出底层 sql 语句 --> <property name="hibernate.show_sql">true</property> <!-- 输出底层 sql 语句格式 --> <property name="hibernate.format_sql">true</property> <!-- Hibernate 帮助创建表,不是自动创建,而需要配置之后。 update:如果已经有表,就更新,如果没有,就自动创建 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 配置数据库方言,让 Hibernate 框架识别不同数据库自己特有的语句 如:在 MySQL 中实现分页的关键字 limit,只能在 MySQL 中使用,而 在 Oracle 中实现分页的关键字则是 rownum --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 配置 Session 绑定本地线程 --> <property name="hibernate.current_session_context_class">thread</property> <!-- 第三部分:引入映射配置文件,把映射配置文件放到核心配置文件(必须) --> <mapping resource="com/siwuxie095/entity/User.hbm.xml"/> <mapping resource="com/siwuxie095/entity/Role.hbm.xml"/> </session-factory> </hibernate-configuration> |
【made by siwuxie095】