程序员技术栈

【Java中级】10.0 SSH之Hibernate框架(七)—

2020-02-07  本文已影响0人  bobokaka

采用两个一对多的方式部署。

为什么?请参考上一篇文章:
【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;
image.png

角色表

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;
image.png

中间表,需要强调的是中间表的两个属性同时是主键,也同时是外键

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;
image.png
建好后,E-R图如下:
image.png
2.0 创建实体
2.1 基本构建
image.png

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 创建映射
image.png
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 编写测试类
image.png

新建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。


image.png

本案例中,一般是用户选角色,因此需要设置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>

执行:


image.png

查看数据库:


image.png
image.png
image.png

以上代码中两边都有保存,如果只保存一边,是否可以?
答案是不可以,具体代码略。会报瞬时态异常错误。
下面进行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();
    }

执行:


image.png

数据库存入正常。

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();
    }

执行:


image.png
5.0 多对多的级联删除(基本用不上)

为什么用不上?
**比如,学生选课程,把学生删掉,级联删除的话,会把相应的课程也删掉;把课程删掉,选这门课的学生的数据也会被删掉,这样做肯定是不合理的。

但是,Hibernate支持这样的级联删除。

5.1 删除用户,级联删除角色
image.png

如图,删除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&amp;serverTimezone=UTC</property>
        <!-- &符号在Hibernate不可用,需写成&amp;使用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

上一篇 下一篇

猜你喜欢

热点阅读