- 【Java中级】10.0 SSH之Hibernate框架(七)—
- 【Java中级】6.0 SSH之Hibernate框架(二)——
- 【Java中级】8.5 SSH之Hibernate框架(五)——
- 【Java中级】9.0 SSH之Hibernate框架(六)——
- 【Java中级】8.0 SSH之Hibernate框架(四)——
- 【Java中级】11.0 SSH之Hibernate框架(八)—
- 【Java中级】12.0 SSH之Hibernate框架(九)—
- 【Java中级】13.0 SSH之Hibernate框架(十)—
- 【Java中级】5.0 SSH之Hibernate框架(一)——
- 【Java中级】7.0 SSH之Hibernate框架(三)——
采用两个一对多的方式部署。
为什么?请参考上一篇文章:
【Java中级】9.0 SSH之Hibernate框架(六)——一对多关联映射的配置和级联操作
1.0 创建表
用户表
CREATE TABLE `sys_user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) COMMENT '用户账号',
`user_name` varchar(64) COMMENT '用户名称',
`user_password` varchar(32) COMMENT '用户密码',
`user_state` char(1) COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

角色表
CREATE TABLE `sys_role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

中间表,需要强调的是中间表的两个属性同时是主键,也同时是外键。
CREATE TABLE `sys_user_role` (
`role_id` bigint(32) NOT NULL COMMENT '角色id',
`user_id` bigint(32) NOT NULL COMMENT '用户id',
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_role_user_id` (`user_id`),
CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

建好后,E-R图如下:

2.0 创建实体
2.1 基本构建

User.java
package com.edp.hibernate.domain;
/**
*
* @Title: User.java
* @Package com.edp.hibernate.domain
* @author EdPeng
* @version 创建时间 2020年2月5日下午10:37:03
* @Description 用户的实体
* @version V1.0
* CREATE TABLE `sys_user` (
* `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
* `user_code` varchar(32) COMMENT '用户账号',
* `user_name` varchar(64) COMMENT '用户名称',
* `user_password` varchar(32) COMMENT '用户密码',
* `user_state` char(1) 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;
}
}
Role.java
package com.edp.hibernate.domain;
/**
*
* @Title: Role.java
* @Package com.edp.hibernate.domain
* @author EdPeng
* @version 创建时间 2020年2月5日下午10:37:32
* @Description 角色的实体
* @version V1.0
* 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;
}
}
到这里,实体创建完毕,关于工程文件其他内容请参考上一篇文章:
【Java中级】9.0 SSH之Hibernate框架(六)——一对多关联映射的配置和级联操作
到这里,还需要处理如何构建多对多的关系。
2.2 表示一个用户选择多个角色
进一步完善User.java
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String 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 void setUsers(Set<User> users) {
this.users = users;
}
…………
@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 + ", roles=" + roles + "]";
}
}
完善Role.java
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
// 一个角色被多个用户选择
// 放置的是用户的集合
private Set<User> users = new HashSet<User>();
public Set<User> getUsers() {
return users;
}
…………
@Override
public String toString() {
return "Role [role_id=" + role_id + ", role_name=" + role_name + ", role_memo=" + role_memo + ", users=" + users
+ "]";
}
}
3.0 创建映射

3.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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.User" table="sys_user" catalog="hibernate0204">
<!-- name:哪个类,全路径,table:哪个表 catalog 哪个数据库 -->
<!-- Id:建立类中的属性与表中的主键对应 -->
<id name="user_id" column="user_id">
<!-- name:在类中的名字 column:表中的字段;此处为一样的名称 -->
<generator class="native" />
<!-- 组件都有一种生成策略,此处使用一种本地策略。 -->
</id>
<!-- 建立类中的普通属性和表的字段的对应 -->
<!-- 除了主键以外的属性,都用property -->
<property name="user_code" />
<property name="user_name" />
<property name="user_password" />
<property name="user_state" />
</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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
<!-- name:哪个类,全路径,table:哪个表 catalog 哪个数据库 -->
<!-- Id:建立类中的属性与表中的主键对应 -->
<id name="role_id" column="role_id">
<!-- name:在类中的名字 column:表中的字段;此处为一样的名称 -->
<generator class="native" />
<!-- 组件都有一种生成策略,此处使用一种本地策略。 -->
</id>
<!-- 建立类中的普通属性和表的字段的对应 -->
<!-- 除了主键以外的属性,都用property -->
<property name="role_name" />
<property name="role_memo" />
</class>
</hibernate-mapping>
3.2 构建映射关系
接下来,需要建立两者之间多对多的映射关系。
修改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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.User" table="sys_user" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:d对方的对象集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="roles" table="sys_user_role">
<!-- key标签
column:当前的对象对应的中间表的外键的名称
-->
<key column="user_id"></key>
<!-- many-to-many标签
class:对方的类的全路径
column:对方的对象在中间表中的外键的名称
-->
<many-to-many class="com.edp.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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:对方的集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="users" table="sys_user_role">
<!-- key标签
column:当前的对象对应中间表的外键的名称
-->
<key column="role_id"/>
<!-- one-to-many标签
class:多的一方的类的全路径
column:对方的对象在中间表中的外键
-->
<many-to-many class="com.edp.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
3.3 修改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>
…………
<!-- 告诉核心配置文件,我要加载哪个映射,引入4个 -->
<mapping resource="com/edp/hibernate/domain/User.hbm.xml" />
<mapping resource="com/edp/hibernate/domain/Role.hbm.xml" />
</session-factory>
</hibernate-configuration>
4.0 编写测试类

新建Hibernatedemo2.java
package com.edp.hibernate.demo2;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.domain.Role;
import com.edp.hibernate.domain.User;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @Title: Hibernatedemo2.java
* @Package com.edp.hibernate.demo2
* @author EdPeng
* @version 创建时间 2020年2月6日下午9:43:26
* @Description 测试Hibernate多对多的映射
* @version V1.0
*/
public class Hibernatedemo2 {
@Test
/**
*
* @Title: demo
* @Description: 保存多条记录:保存多个用户和角色
* @param
* @return void
* @throws
*
*/
public void demo() {
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);
//保存操作:多对多建立了双向的关系,必须有一方放弃外键的维护
//因为存在中间表,每次修改都是向中间表插入新的值
//不可能存入一次role_id =1 user_id=1 ,再一次存入role_id =1 user_id=1
//一般是被动方放弃外键维护权。
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
transaction.commit();
}
}
以上代码运行报错。
保存操作:多对多建立了双向的关系,必须有一方放弃外键的维护,因为存在中间表,每次修改都是向中间表插入新的值,不可能存入一次role_id =1 user_id=1 ,再一次存入role_id =1 user_id=1。

本案例中,一般是用户选角色,因此需要设置Role.hbm.xml文件中的<set >标签设置inverse="true"属性,代码如下:
<?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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:对方的集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="users" table="sys_user_role" inverse="true">
<!-- key标签
column:当前的对象对应中间表的外键的名称
-->
<key column="role_id"/>
<!-- one-to-many标签
class:多的一方的类的全路径
column:对方的对象在中间表中的外键
-->
<many-to-many class="com.edp.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
执行:

查看数据库:



以上代码中两边都有保存,如果只保存一边,是否可以?
答案是不可以,具体代码略。会报瞬时态异常错误。
下面进行Hibernate的多对多操作
4.0 多对多的级联保存和更新
和Hibernate一对多的操作和设置是一样的。
4.1保存用户,级联保存联系人
在User.hbm.xml中的set上配置cascade="save-update"
<?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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.User" table="sys_user" catalog="hibernate0204">
…………
<!-- cascade="save-update,delete" inverse="true" -->
<set name="roles" table="sys_user_role" cascade="save-update">
<!-- key标签
column:当前的对象对应的中间表的外键的名称
-->
<key column="user_id"></key>
<!-- many-to-many标签
class:对方的类的全路径
column:对方的对象在中间表中的外键的名称
-->
<many-to-many class="com.edp.hibernate.domain.Role" column="role_id" />
</set>
</class>
</hibernate-mapping>
Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo2
* @Description: 多对多的级联保存
* 保存用户,级联保存联系人;在用户的映射文件中配置。
* 在User.hbm.xml中的set上配置cascade="save-update"
* @param
* @return void
* @throws
*
*/
private void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user1 = new User();
user1.setUser_name("张铁柱");
Role role1 = new Role();
role1.setRole_name("新东方");
session.save(user1);
transaction.commit();
}
执行:

数据库存入正常。
4.2 保存联系人,级联保存用户
在Role.hbm.xml中的set上配置cascade="save-update"
<?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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:对方的集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="users" table="sys_user_role" inverse="true" cascade="save-update">
<!-- key标签
column:当前的对象对应中间表的外键的名称
-->
<key column="role_id"/>
<!-- one-to-many标签
class:多的一方的类的全路径
column:对方的对象在中间表中的外键
-->
<many-to-many class="com.edp.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo3
* @Description: 多对多的级联保存
* 保存联系人,级联保存用户;在角色的映射文件中配置。
* 在Role.hbm.xml中的set上配置cascade="save-update"
* @param
* @return void
* @throws
*
*/
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user1 = new User();
user1.setUser_name("来来来");
Role role1 = new Role();
role1.setRole_name("二狗子");
// 设置双向的关联关系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
session.save(role1);
transaction.commit();
}
执行:

5.0 多对多的级联删除(基本用不上)
为什么用不上?
**比如,学生选课程,把学生删掉,级联删除的话,会把相应的课程也删掉;把课程删掉,选这门课的学生的数据也会被删掉,这样做肯定是不合理的。
但是,Hibernate支持这样的级联删除。
5.1 删除用户,级联删除角色

如图,删除3号用户,级联删除4号和5号角色。
修改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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.User" table="sys_user" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:d对方的对象集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!-- key标签
column:当前的对象对应的中间表的外键的名称
-->
<key column="user_id"></key>
<!-- many-to-many标签
class:对方的类的全路径
column:对方的对象在中间表中的外键的名称
-->
<many-to-many class="com.edp.hibernate.domain.Role" column="role_id" />
</set>
</class>
</hibernate-mapping>
在Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo4
* @Description: 删除用户,级联删除角色
* 在User.hbm.xml中的set上配置cascade="delete"
* @param
* @return void
* @throws
*
*/
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class,1l);
session.delete(user);
//报错,无法运行
transaction.commit();
}
报错无法运行,有时间再调试解决bug。
5.2 删除角色,级联删除用户
在Role.hbm.xml的set标签中添加cascade="delete" 属性。
<?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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
…………
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:对方的集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="users" table="sys_user_role" cascade="save-update,delete" inverse="true">
<!-- key标签
column:当前的对象对应中间表的外键的名称
-->
<key column="role_id" />
<!-- one-to-many标签
class:多的一方的类的全路径
column:对方的对象在中间表中的外键
-->
<many-to-many class="com.edp.hibernate.domain.User" column="user_id" />
</set>
</class>
</hibernate-mapping>
在Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo5
* @Description: 删除角色,级联删除用户
* 在Role.hbm.xml中的set上配置cascade="delete"
* @param
* @return void
* @throws
*
*/
public void demo5() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Role role = session.get(Role.class, 2l);
session.delete(role);
// 报错,无法运行
transaction.commit();
}
无法运行,暂时调试不出来,推断是mySQL升级导致约束关系逻辑发生改变,无法再这样操作。
6.0 多对多的其他操作
6.1 给用户选择角色
Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo7
* @Description: 给用户改选角色
* @param
* @return void
* @throws
*
*/
public void demo7() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给4号用户原有的5号角色改为4号角色
User user = session.get(User.class, 4l);
Role role = session.get(Role.class, 4l);
Role role2 = session.get(Role.class, 5l);
user.getRoles().remove(role2);
user.getRoles().add(role);
transaction.commit();
}
6.1 给用户改选角色
Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo6
* @Description: 给用户添加角色
* @param
* @return void
* @throws
*
*/
public void demo6() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给3号用户改选6号角色
User user = session.get(User.class, 3l);
Role role = session.get(Role.class, 6l);
user.getRoles().add(role);
transaction.commit();
}
6.1 给用户删除角色
Hibernatedemo2.java中新建方法:
@Test
/**
*
* @Title: demo8
* @Description: 给用户删除角色
* @param
* @return void
* @throws
*
*/
public void demo8() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给3号用户删除4号角色
User user = session.get(User.class, 3l);
Role role = session.get(Role.class, 4l);
user.getRoles().remove(role);
transaction.commit();
}
7.0 完整代码
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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.Role" table="sys_role" catalog="hibernate0204">
<!-- name:哪个类,全路径,table:哪个表 catalog 哪个数据库 -->
<!-- Id:建立类中的属性与表中的主键对应 -->
<id name="role_id" column="role_id">
<!-- name:在类中的名字 column:表中的字段;此处为一样的名称 -->
<generator class="native" />
<!-- 组件都有一种生成策略,此处使用一种本地策略。 -->
</id>
<!-- 建立类中的普通属性和表的字段的对应 -->
<!-- 除了主键以外的属性,都用property -->
<property name="role_name" column="role_name" />
<property name="role_memo" column="role_memo" />
<!-- 配置一对多的关系:放置的是多的一方的集合 -->
<!-- 联系人是多,客户是一 -->
<!-- set标签
name:对方的集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="users" table="sys_user_role" cascade="save-update,delete" inverse="true">
<!-- key标签
column:当前的对象对应中间表的外键的名称
-->
<key column="role_id" />
<!-- one-to-many标签
class:多的一方的类的全路径
column:对方的对象在中间表中的外键
-->
<many-to-many class="com.edp.hibernate.domain.User" column="user_id" />
</set>
</class>
</hibernate-mapping>
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>
<!-- hibernate-mapping是根标签 -->
<!-- 建立类与表的映射 -->
<class name="com.edp.hibernate.domain.User" table="sys_user" catalog="hibernate0204">
<!-- name:哪个类,全路径,table:哪个表 catalog 哪个数据库 -->
<!-- Id:建立类中的属性与表中的主键对应 -->
<id name="user_id" column="user_id">
<!-- name:在类中的名字 column:表中的字段;此处为一样的名称 -->
<generator class="native" />
<!-- 组件都有一种生成策略,此处使用一种本地策略。 -->
</id>
<!-- 建立类中的普通属性和表的字段的对应 -->
<!-- 除了主键以外的属性,都用property -->
<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:d对方的对象集合的属性名称
cascade:级联,用逗号隔开,就同时拥有保存或更新、删除功能
inverse:放弃外键维护权,true是确定放弃外键维护权。默认的false是不放弃。
table: 多对多的关系需要使用中间表,放的是中间表的名称
-->
<!-- cascade="save-update,delete" inverse="true" -->
<set name="roles" table="sys_user_role" cascade="save-update,delete">
<!-- key标签
column:当前的对象对应的中间表的外键的名称
-->
<key column="user_id"/>
<!-- many-to-many标签
class:对方的类的全路径
column:对方的对象在中间表中的外键的名称
-->
<many-to-many class="com.edp.hibernate.domain.Role" column="role_id" />
</set>
</class>
</hibernate-mapping>
Hibernatedemo2.java
package com.edp.hibernate.demo2;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.domain.Role;
import com.edp.hibernate.domain.User;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @Title: Hibernatedemo2.java
* @Package com.edp.hibernate.demo2
* @author EdPeng
* @version 创建时间 2020年2月6日下午9:43:26
* @Description 测试Hibernate多对多的映射
* @version V1.0
*/
public class Hibernatedemo2 {
@Test
/**
*
* @Title: demo
* @Description: 保存多条记录:保存多个用户和角色
* @param
* @return void
* @throws
*
*/
public void demo1() {
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);
// 保存操作:多对多建立了双向的关系,必须有一方放弃外键的维护
// 因为存在中间表,每次修改都是向中间表插入新的值
// 不可能存入一次role_id =1 user_id=1 ,再一次存入role_id =1 user_id=1
// 一般是被动方放弃外键维护权。
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
session.save(role3);
transaction.commit();
}
@Test
/**
*
* @Title: demo2
* @Description: 多对多的级联保存
* 保存用户,级联保存联系人;在用户的映射文件中配置。
* 在User.hbm.xml中的set上配置cascade="save-update"
* @param
* @return void
* @throws
*
*/
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user1 = new User();
user1.setUser_name("张铁柱");
Role role1 = new Role();
role1.setRole_name("新东方");
// 设置双向的关联关系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
session.save(user1);
transaction.commit();
}
@Test
/**
*
* @Title: demo3
* @Description: 多对多的级联保存
* 保存联系人,级联保存用户;在角色的映射文件中配置。
* 在Role.hbm.xml中的set上配置cascade="save-update"
* @param
* @return void
* @throws
*
*/
public void demo3() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user1 = new User();
user1.setUser_name("来来来");
Role role1 = new Role();
role1.setRole_name("二狗子");
// 设置双向的关联关系
user1.getRoles().add(role1);
role1.getUsers().add(user1);
session.save(role1);
transaction.commit();
}
@Test
/**
*
* @Title: demo4
* @Description: 删除用户,级联删除角色
* 在User.hbm.xml中的set上配置cascade="delete"
* @param
* @return void
* @throws
*
*/
public void demo4() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 1l);
session.delete(user);
// 报错,无法运行
transaction.commit();
}
@Test
/**
*
* @Title: demo5
* @Description: 删除角色,级联删除用户
* 在Role.hbm.xml中的set上配置cascade="delete"
* @param
* @return void
* @throws
*
*/
public void demo5() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Role role = session.get(Role.class, 2l);
session.delete(role);
// 报错,无法运行
transaction.commit();
}
@Test
/**
*
* @Title: demo6
* @Description: 给用户添加角色
* @param
* @return void
* @throws
*
*/
public void demo6() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给3号用户改选6号角色
User user = session.get(User.class, 3l);
Role role = session.get(Role.class, 6l);
user.getRoles().add(role);
transaction.commit();
}
@Test
/**
*
* @Title: demo7
* @Description: 给用户改选角色
* @param
* @return void
* @throws
*
*/
public void demo7() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给4号用户原有的5号角色改为4号角色
User user = session.get(User.class, 4l);
Role role = session.get(Role.class, 4l);
Role role2 = session.get(Role.class, 5l);
user.getRoles().remove(role2);
user.getRoles().add(role);
transaction.commit();
}
@Test
/**
*
* @Title: demo8
* @Description: 给用户删除角色
* @param
* @return void
* @throws
*
*/
public void demo8() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 给3号用户删除4号角色
User user = session.get(User.class, 3l);
Role role = session.get(Role.class, 4l);
user.getRoles().remove(role);
transaction.commit();
}
}
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> -->
<!-- MySQL8.0以后,用的连接驱动改变了,driver必须加上.cj -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!--MySQL8.0以后, url为jdbc:mysql://localhost:3306/test后面加?useSSL=false&serverTimezone=UTC -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate0204?useSSL=false&serverTimezone=UTC</property>
<!-- &符号在Hibernate不可用,需写成&使用MySQL8Dialect -->
<!-- jdbc:mysql://localhost:3306/hibernate_learn连接本地库可以省略,所以这里用/// -->
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">bywwcnll</property>
<!-- 配置hibernate的方言 告诉hibernate要识别MySQL的“方言”(这样,hibernate就能帮开发者生成MySQL识别的SQL语句) -->
<!-- name="hibernate.dialect":表示Hibernate的方言就是MySQL -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL8Dialect</property>
<!--<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> -->
<!--<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> -->
<!-- 可选配置 -->
<!-- 打印SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL,使SQL语句在打印的时候更加漂亮 -->
<property name="hibernate.format_sql">true</property>
<!-- 自动创建表 -->
<!--<property name="hibernate.hbm2ddl.auto">update create</property> -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 配置C3P0连接池 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="hibernate.c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="hibernate.c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都验证连接是否可用 -->
<property name="hibernate.c3p0.validate">true</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位 -->
<property name="c3p0.idle_test_period">3000</property>
<!-- 事务隔离级别 hibernate.connection.isolation
1->Read uncommitted isolation
2->read committed isolation
4->Repeatable read isolation(MySQL默认级别)
8->Serializable isolation -->
<property name="hibernate.connection.isolation">4</property>
<!-- 配置当前线程绑定的Session -->
<!-- 用于指定Session的管理方式
thread:Session对象的生命周期与本地线程绑定
jta:Session对象的生命周期与JTA事务(跨数据库的事务)绑定
managed:Hibernate委托程序来管理Session对象的生命周期 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 告诉核心配置文件,我要加载哪个映射,引入4个 -->
<mapping resource="com/edp/hibernate/domain/Customer.hbm.xml" />
<mapping resource="com/edp/hibernate/domain/LinkMan.hbm.xml" />
<mapping resource="com/edp/hibernate/domain/User.hbm.xml" />
<mapping resource="com/edp/hibernate/domain/Role.hbm.xml" />
</session-factory>
</hibernate-configuration>
END
网友评论