hibernate多对多关联ManyToMany

hibernate一对多关联,hibernate OneToMany

知兮丶青
阅读(1178) 2017-12-27
hibernate多对多关联ManyToMany
hibernate多对多关联ManyToMany

多对多关联应用场景,比如一个学生可以选修多门课程,一门课程可以被多个学生选修,这个时候表就应该设计为多对多。再如经典的用户、角色、权限表关系3个表互相之间都是多对多关联关系。


多对多关联,使用@ManyToMany


多对多单向

用户表:User

多对多关联,注解@ManyToMany单向

默认情况下,hibernate会自动的创建一张中间表,来维护多对多的关系。

默认中间表的名称:user_role中间表,字段的名称user_id和role_id

如果想要换表名和字段名称,注解如下:

@JoinTable(name="t_u_r"),指定中间表的表名

joinColumns={@JoinColumn(name="u_id")},指定当前对象的外键

inverseJoinColumns={@JoinColumn(name="r_id")},指定关联对象的外键

package com.weizhixi.entity;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;

@Entity
public class User {
   private int id;
   private String name;
   private Set<Role> role = new HashSet<Role>();

   @Id
   @GeneratedValue
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @ManyToMany
   /*@JoinTable(name="t_u_r",
         joinColumns={@JoinColumn(name="u_id")},
         inverseJoinColumns={@JoinColumn(name="r_id")})*/
   @JoinTable
   public Set<Role> getRole() {
      return role;
   }
   public void setRole(Set<Role> role) {
      this.role = role;
   }
}

角色表:Role

多对多单向,无需配置。

package com.weizhixi.entity;

import javax.persistence.*;

@Entity
public class Role {
   private int id;
   private String name;

   @Id
   @GeneratedValue
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
}


添加数据

session = sessionFactory.getCurrentSession();
session.beginTransaction();

//创建用户
User user = new User();
user.setName("admin");

//设置角色
Set<Role> roles = new HashSet<Role>();
Role manager = new Role();
manager.setName("manager");//管理员
Role editor = new Role();
editor.setName("editor");//编辑员
roles.add(manager);
roles.add(editor);
//分配角色给用户
user.setRole(roles);

//保存角色
session.save(manager);
session.save(editor);
//保存用户
session.save(user);

session.getTransaction().commit();

添加角色发送的SQL:

Hibernate: insert into Role (name) values (?)

Hibernate: insert into Role (name) values (?)

新增用户后再给用户分配发送的SQL:

Hibernate: insert into User (name) values (?)

Hibernate: insert into User_Role (User_id, role_id) values (?, ?)

Hibernate: insert into User_Role (User_id, role_id) values (?, ?)


查询数据

session = sessionFactory.getCurrentSession();
session.beginTransaction();

User user = (User)session.get(User.class, 1);
System.out.println(user.getName());
for(Role role : user.getRole()){
   System.out.println("\t"+role.getName());
}

session.getTransaction().commit();

默认时查询多对象时Hibernate也是会采用懒加载,输出:

Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from User user0_ where user0_.id=?
admin
Hibernate: select role0_.User_id as User1_1_, role0_.role_id as role2_1_, role1_.id as id1_0_, role1_.name as name1_0_ from User_Role role0_ left outer join Role role1_ on role0_.role_id=role1_.id where role0_.User_id=?
	manager
	editor

用户表:

mysql> select * from user;
+----+-------+
| id | name  |
+----+-------+
|  1 | admin |
+----+-------+
1 row in set (0.00 sec)

角色表:

mysql> select * from role;
+----+---------+
| id | name    |
+----+---------+
|  1 | manager |
|  2 | editor  |
+----+---------+
2 rows in set (0.00 sec)

用户角色中间表(维护多对多关系):

mysql> select * from user_role;
+---------+---------+
| User_id | role_id |
+---------+---------+
|       1 |       1 |
|       1 |       2 |
+---------+---------+
2 rows in set (0.00 sec)



多对多双向

用户表:User

这个表不用变。

package com.weizhixi.entity;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;

@Entity
public class User {
   private int id;
   private String name;
   private Set<Role> role = new HashSet<Role>();

   @Id
   @GeneratedValue
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @ManyToMany
   /*@JoinTable(name="t_u_r",
         joinColumns={@JoinColumn(name="u_id")},
         inverseJoinColumns={@JoinColumn(name="r_id")})*/
   @JoinTable
   public Set<Role> getRole() {
      return role;
   }
   public void setRole(Set<Role> role) {
      this.role = role;
   }
}

角色表:Role

加入(mappedBy="role"),表示由User那一方来进行维护关系。

package com.weizhixi.entity;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Role {
   private int id;
   private String name;
   private Set<User> user = new HashSet<User>();

   @Id
   @GeneratedValue
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   @ManyToMany(mappedBy="role")
   public Set<User> getUser() {
      return user;
   }
   public void setUser(Set<User> user) {
      this.user = user;
   }
}


查询数据:

session = sessionFactory.getCurrentSession();
session.beginTransaction();

Role role = (Role)session.get(Role.class, 1);
System.out.println(role.getName());
for(User user : role.getUser()){
   System.out.println("\t"+user.getName());
}

session.getTransaction().commit();

查角色:默认时查询多对象时Hibernate也是会采用懒加载,输出:

Hibernate: select role0_.id as id1_0_, role0_.name as name1_0_ from Role role0_ where role0_.id=?
manager
Hibernate: select user0_.role_id as role2_1_, user0_.user_id as user1_1_, user1_.id as id0_0_, user1_.name as name0_0_ from user_role user0_ left outer join User user1_ on user0_.user_id=user1_.id where user0_.role_id=?
	admin


删除数据:

删除用户(删除用户1):

User user = new User();
user.setId(1);
session.delete(user);

删除用户发送的SQL(删除中间表关系后再删除用户):

Hibernate: delete from User_Role where user_id=?
Hibernate: delete from User where id=?

但删除角色是,要先取消用户对角色的关联。因为Role不是主导方,直接删除角色会抛出异常:Cannot delete or update a parent row: a foreign key constraint fails (`test`.`user_role`, CONSTRAINT `FK8B9F886A3B5A79D5` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`))。如果你双方都需要主导权配置就应该改为:

User表:

@ManyToMany
@JoinTable(name="user_role",
      joinColumns={@JoinColumn(name="user_id")},
      inverseJoinColumns={@JoinColumn(name="role_id")})
private Set<Role> role = new HashSet<Role>();

Role表:

@ManyToMany(mappedBy="role")
@JoinTable(name="user_role",
      joinColumns={@JoinColumn(name="role_id")},
      inverseJoinColumns={@JoinColumn(name="user_id")})
private Set<User> user = new HashSet<User>();



原创文章,转载请注明出处:https://www.weizhixi.com/article/43.html