Hibernate关系映射(七)多对多双向关联@ManyToMany Annotation方式

本篇介绍多对多的双向关联,也是Hibernate关系映射的结尾篇,后续篇章会介绍Hibernate的懒加载机制和级联相关操作。


首先还是来模拟一个实际应用的场景,在之前开发过的RBAC模型中,有这样一个关系,用户组中包含多个用户,每一个用户可以属于多个用户组,那么这就是一个多对多的关系,而我又需要从当前用户组读取到包含哪些用户,又需要从当前用户获取他在哪些组中。那么就需要建立双向关联。
Entity:UserGroup
Attr:id(Integer)
name(String)
users(Set< User >)

Entity:User
Attr:id(Integer)
name(String)
userGroups(Set< UserGroup >)


下面是数据库表结构:
这里写图片描述
可以看到,t_usergroup_user作为中间表,里面有一个字段userGroupId作为外键指向了t_usergroup表,参考了该表的id,另一个外键userId指向了t_user表,参考了该表的id。这样的结构,和单向关联没区别,下面就看实体类的书写。


import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="t_usergroup")
public class UserGroup {

    private Integer id;
    private String name;
    private Set<User> users = new HashSet<User>();

    public UserGroup() {
        super();
    }

    public UserGroup(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToMany
    @JoinTable(name="t_usergroup_user",
            joinColumns={@JoinColumn(name="userGroupId")},
            inverseJoinColumns={@JoinColumn(name="userId")})
    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }


}

@JoinTable(name=”t_usergroup_user”中间表的名字
joinColumns={@JoinColumn(name=”userGroupId”)},中间表参考该实体id的那个外键的名称
inverseJoinColumns={@JoinColumn(name=”userId”)})对方实体在中间表中的名称

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="t_user")
public class User {

    private Integer id;
    private String name;
    private Set<UserGroup> userGroups= new HashSet<UserGroup>();

    public User() {
        super();
    }

    public User(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToMany(mappedBy="users")
    public Set<UserGroup> getUserGroups() {
        return userGroups;
    }

    public void setUserGroups(Set<UserGroup> userGroups) {
        this.userGroups = userGroups;
    }


}

@ManyToMany(mappedBy=”users”)既然是双向关联,那么就要设置mappedBy属性,该属性指被UserGroup实体中的users这个属性映射。


实体类书写完毕后,我们来进行CRUD的测试
首先是添加数据的测试,testCreate()

     @Test
     public void testCreate(){
      Session session = sessionFactory.getCurrentSession();
      session.beginTransaction();

      UserGroup ug1 = new UserGroup();
      ug1.setName("超级管理员组");

      UserGroup ug2 = new UserGroup();
      ug2.setName("普通用户组");

      User u1 = new User();
      u1.setName("admin");

      User u2 = new User();
      u2.setName("wan");

      Set<User> userSet1 = new HashSet<User>();
      userSet1.add(u1);
      userSet1.add(u2);

      Set<User> userSet2 = new HashSet<User>();
      userSet2.add(u1);

      //超级管理员组只有一个admin
      ug1.setUsers(userSet2);

      //普通用户组包含两个用户
      ug2.setUsers(userSet1);

      session.saveOrUpdate(ug1);
      session.saveOrUpdate(ug2);
      session.saveOrUpdate(u1);
      session.saveOrUpdate(u2);

      session.getTransaction().commit();
     }

结果:
这里写图片描述
这里写图片描述
这里写图片描述


接下来是读取操作,testRead()

     @Test
     public void testRead(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         //用户组---->用户
         UserGroup ug = (UserGroup) session.load(UserGroup.class, 2);
         System.out.println("名称:"+ug.getName());
         for(User u : ug.getUsers()){
             System.out.println("包含了以下用户:"+u.getName());
         }

         //用户---->用户组
         User u = (User) session.load(User.class, 1);
         System.out.println("用户名称:"+u.getName());
         for(UserGroup ugg : u.getUserGroups()){
             System.out.println("在以下用户组中:"+ugg.getName());
         }

         session.getTransaction().commit();
     }

结果:

Hibernate: 
    select
        usergroup0_.id as id6_0_,
        usergroup0_.name as name6_0_ 
    from
        t_usergroup usergroup0_ 
    where
        usergroup0_.id=?
名称:普通用户组
Hibernate: 
    select
        users0_.userGroupId as userGrou1_1_,
        users0_.userId as userId1_,
        user1_.id as id7_0_,
        user1_.name as name7_0_ 
    from
        t_usergroup_user users0_ 
    left outer join
        t_user user1_ 
            on users0_.userId=user1_.id 
    where
        users0_.userGroupId=?
包含了以下用户:admin
包含了以下用户:wan
用户名称:admin
Hibernate: 
    select
        usergroups0_.userId as userId1_,
        usergroups0_.userGroupId as userGrou1_1_,
        usergroup1_.id as id6_0_,
        usergroup1_.name as name6_0_ 
    from
        t_usergroup_user usergroups0_ 
    left outer join
        t_usergroup usergroup1_ 
            on usergroups0_.userGroupId=usergroup1_.id 
    where
        usergroups0_.userId=?
在以下用户组中:超级管理员组
在以下用户组中:普通用户组

可以看到双向关联从哪边都可以找到另一边


接下来是修改操作,testUpdate()

     @Test
     public void testUpdate(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         UserGroup ug1 = (UserGroup) session.load(UserGroup.class, 1);
         ug1.setName("Super User Group");

         UserGroup ug2 = (UserGroup) session.load(UserGroup.class, 2);
         ug2.setName("Normal User Group");

         session.saveOrUpdate(ug1);
         session.saveOrUpdate(ug2);

         session.getTransaction().commit();
     }

结果:
这里写图片描述


最后是删除操作,testDelete()

     @Test
     public void testDelete(){
         Session session = sessionFactory.getCurrentSession();
         session.beginTransaction();

         UserGroup ug2 = (UserGroup) session.load(UserGroup.class, 2);
         ug2.setUsers(null);

         session.delete(ug2);

         session.getTransaction().commit();
     }

结果:

Hibernate: 
    delete 
    from
        t_usergroup_user 
    where
        userGroupId=?
Hibernate: 
    delete 
    from
        t_usergroup 
    where
        id=?

这次我们看show sql出来的语句,先删除了中间表中的关系,再删除用户组,这样的操作是对的。


那么Hibernate关系映射系列就介绍到这里,希望对你有所帮助

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hibernate是一个Java持久化框架,它能够将Java对象映射到数据库中的表格,同时支持各种关系数据库,如MySQL、Oracle等。在Hibernate中,对于一对一、一对多和多对多关系,我们可以通过以下方式进行映射。 一对一关系:在Hibernate中,可以通过主键关联和外键关联来实现一对一关系映射。主键关联是指两个实体之间的关联通过主键来进行,可以使用@PrimaryKeyJoinColumn注解将两个实体关联起来。外键关联是指通过一个实体引用另一个实体的主键作为外键,使用@JoinColumn注解来指定外键属性。 一对多关系:在Hibernate中,一对多关系通常通过外键关联来实现。在一的一方,使用@OneToMany注解来定义一对多关系,同时使用@JoinColumn注解指定外键属性。在多的一方,使用@ManyToOne注解来定义多对一关系,并使用@JoinColumn注解指定外键属性。 多对多关系:在Hibernate中,多对多关系通常通过中间表来实现。在多对多的两个实体中,使用@ManyToMany注解来定义多对多关系。同时,需要在中间表中创建两个外键,分别与两个实体的主键关联,并使用@JoinTable注解来指定中间表的表名和两个外键的列名。 总结:通过Hibernate的注解方式,可以方便地实现一对一、一对多和多对多关系映射。通过合理地使用注解,可以减少编写映射文件的工作量,提高开发效率。同时,Hibernate还提供了在运行时自动生成表结构的功能,可以根据Java实体类来动态创建或更新对应的数据库表格,从而提高系统的可维护性和灵活性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值