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