Hibernate 多对多的关系映射,详解(代码
direct messages to file mylog.log
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
set log levels - for more verbose logging change 'info' to 'debug'
error warn info debug trace
log4j.rootLogger= info, stdout
(4)工具类
package com.itzheng.hibernate.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/*
Hibernate 的工具类
做 hibernate 的小练习,对 configuration 的 configure()方法很好奇,为啥创建的对象还要执行这个方法呢。
Configuration cfg = new Configuration().configure();
原来 configure()方法默认会在 classpath 下面寻找 hibernate.cfg.xml 文件,
如果没有找到该文件,系统会打印如下信息并抛出 HibernateException 异常。
其实不使用 configure()方法也可以
Configuration cfg = new Configuration();
这时 hibernate 会在 classpath 下面寻找 hibernate.properties 文件,
如果没有找到该文件,系统会打印如下信息并抛出 HibernateException 异常。
*/
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static {
cfg = new Configuration().configure();// 获取与数据库的链接的配置文件
sf = cfg.buildSessionFactory();//开启事务建立与数据库之间的链接
}
public static Session openSession() {
return sf.openSession();
}
public static Session getCurrentSession() {
return sf.getCurrentSession();
}
}
[](()3、创建实体
(1)创建用户的实体
package com.itzheng.hibernate.domain;
/*
用户的实体
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=1 DEFAULT CHARSET=utf8;
*/
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
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 String getUser_state() {
return user_state;
}
public void setUser_state(String user_state) {
this.user_state = user_state;
}
}
(2)创建角色的实体
package com.itzheng.hibernate.domain;
/*
角色的实体
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=1 DEFAULT CHARSET=utf8;
*/
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
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;
}
}
[](()4、设置多对多的关系(放置对方的集合)
(1)一个用户选择多个角色
同时生成 get 和 set 方法
(2)一个角色被多个用户选择
同时生成 get 和 set 方法
[](()4、创建映射
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>
<class name="com.itzheng.hibernate.domain.User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native" />
</id>
<property name="user_code" column="user_code"/>
<property name="user_name" column="user_name"/>
<property name="user_password" column="user_password"/>
<property name="user_state" column="user_state"/>
<!--
在 set 标签当中有
*name 属性:对方集合的属性名称
table 属性:多对多的关系需要使用中间表,中间表的名称
-->
<set name="roles" table="sys_user_role">
<!--
key 标签的:
column:当前的对象对应中间表的外键的名称。
-->
<key column="user_id"/>
<!--
many-to-many 标签:
*class :对象的类的全路径
*column:对方的对象对应的中间表中的外键名称。
-->
<many-to-many class="com.itzheng.hibernate.domain.Role" column="role_id"/>
</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.itzheng.hibernate.domain.Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<property name="role_name" column="role_name"/>
<property name="role_memo" column="role_memo"/>
<!--
key 标签的:
column:当前的对象对应中间表的外键的名称。
-->
<set name="users" table="sys_user_role">
<!--
key 标签的:
column:当前的对象对应中间表的外键的名称。
-->
<key column="role_id"/>
<!--
many-to-many 标签:
*class :对象的类的全路径
*column:对方的对象对应的中间表中的外键名称。
-->
<many-to-many class="com.itzheng.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
[](()5、将映射添加到核心配置文件
在 hibernate.cfg.xml
[](()二、编写测试类
直接执行下面代码会报错
package com.itzheng.hibernate.demo2;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.itzheng.hibernate.domain.Role;
import com.itzheng.hibernate.domain.User;
import com.itzheng.hibernate.utils.HibernateUtils;
/*
Hibernate 的多对多的映射
*/
public class HibernateDemo2 {
@Test
/*
保存多条记录:保存多个用户和角色
*/
public void demo01() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建 2 个用户
User user1 = new User();
user1.setUser_name("李白");
User user2 = new User();
user2.setUser_name("杜甫");
// 创建 3 个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系,获取到对应的集合将对象添加进去,用户和角色相互对应
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2);
// 保存操作:多对多建立了双向的关系,必须有一方放弃了外键维护
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
transaction.commit();
}
}
报主键重混异常
需要被动方放弃外键维护权,这里是在角色的一方放弃外键维护权
在 Role.hbm.xml 当中的 set 集合当中
设置完后执行
成功执行
[](()三、Hibernate 多对多的一些操作
[](()1、多对多的情况下在不设置级联的情况下,只保存一边会报错
(1)值保存用户(测试代码)
@Test
/*
多对多的一些操作 只是保存一边是否可以,答案在不设置级联的情况下会报,瞬时对象异常
*/
public void demo02() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建 2 个用户
User user1 = new User();
user1.setUser_name("李白");
// 创建 3 个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系,获取到对应的集合将对象添加进去,用户和角色相互对应
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 只保存角色
session.save(user1);
transaction.commit();
}
(2)只保存角色,因为 Role 放弃了外键维护权,保存角色的时候,不影用户,所以不会报错(但是因为在核心配置文件当中是 create 从新建表,所以用户表会被置空)
@Test
/*
多对多的一些操作 只是保存一边是否可以,答案在不设置级联的情况下会报,瞬时对象异常
*/
public void demo02() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建 2 个用户
User user1 = new User();
user1.setUser_name("李白");
// 创建 3 个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系,获取到对应的集合将对象添加进去,用户和角色相互对应
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 只保存用户
//session.save(user1);
//只保存角色
session.save(role1);
transaction.commit();
}
[](()2、多对多的级联保存或者更新
(1) 保存用户,级联保存角色。在用户的映射文件当中配置。
在 User.hbm.xml 中的 set 当中配置 cascade=“save-update”
这是只保存 User 的时候
@Test
/*
多对多的一个级联保存
保存用户,级联保存角色。在用户的映射文件当中配置。
*/
public void demo03() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建 2 个用户
User user1 = new User();
user1.setUser_name("李白");
// 创建 3 个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系,获取到对应的集合将对象添加进去,用户和角色相互对应
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 只保存用户
session.save(user1);
// 只保存角色
//session.save(role1);
transaction.commit();
}
成功执行并插入了数据(一号用户选择了一号角色)
多对多的一个级联保存
(2) 保存角色去,级联保存用户。在角色的映射文件当中配置。
在 Role.hbm.xml 当中
@Test
/*
多对多的一个级联保存
保存角色去,级联保存用户。在角 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 色的映射文件当中配置。
*/
public void demo04() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 创建 2 个用户
User user1 = new User();
user1.setUser_name("李白");
// 创建 3 个角色
Role role1 = new Role();
role1.setRole_name("研发部");
Role role2 = new Role();
role2.setRole_name("市场部");
Role role3 = new Role();
role3.setRole_name("公关部");
// 设置双向的关联关系,获取到对应的集合将对象添加进去,用户和角色相互对应
user1.getRoles().add(role1);
role1.getUsers().add(user1);
// 只保存用户
//session.save(role1);
// 只保存角色
session.save(role1);
transaction.commit();
}
评论