JPA - 双向多对多映射
背景:
使用SpringData + JPA。在权限管理设计表格的时候,要使用双向多对多,但是碰到了很多问题,此篇博客记录一下我的心得。
我对权限管理设计的是一个role表,一个permission表,然后在对表与表之间进行多对多双向关联。
在双向多对多关系中,必须在两表之间指定一个关系维护端,可以通过@ManyToMany中的mappedby来指定关系维护端。
这样解释mappedBy:
在哪个model中的某个注解使用了mappedBy,则该model放弃维持关联关系;如上所示,这里为Category放弃维持关联关系,以Item为主;
在哪个属性上面的注解使用了mappedBy属性,则该注解标注的属性的实体类维持关联关系。在我的例子中,以permission表为主。
避免要踩的坑:
- 要么就在属性上注解,要么就在属性的get方法上添加注解,一定不能同时在两个上添加注解。
- 在permission表的 @JoinTable中:
@JoinTable(
name = "permission_role",
joinColumns = {@JoinColumn(name = "permission_id", referencedColumnName = "permission_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")}
)
name:生成的中间表的名称;
joinColums:映射当前类所在的表在中间表的外键
name:当前类所在的表在中间表的外键名称
referencedColumnName:映射当前类的属性的名称
inverseJoinColumns:映射关联类所在中间表的外键
- 双向多对多要配置懒加载策略,否则在最后测试的时候还会报错。如:
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
以下是role表代码:
package com.wenlot.wenlot.pojo;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* @author : 许兵
* @time : 2019-03-11 19:46:34
* @E-mail : [email protected]
* @Wechat :玖弦与柒墨
* @describe :角色表
*/
@Entity
@Getter
@Setter
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
@Table(name = "role")
public class Role implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "role_id", length = 16)
private Integer id;
/** 角色名称 */
@Column(name = "role_name", length = 32)
private String name;
/** 该条记录的创建时间 */
@CreatedDate
@Column(name = "create_time")
private Date createTime;
/** 该条记录的最近更新时间 */
@LastModifiedDate
@Column(name = "update_time")
private Date updateTime;
@ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Permission> permissions = new HashSet<>();
}
以下是permission表:
package com.wenlot.wenlot.pojo;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* @author : 许兵
* @time : 2019-03-11 19:51:57
* @E-mail : [email protected]
* @Wechat :玖弦与柒墨
* @describe :
*/
@Entity
//@ToString
@Table(name = "permission")
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
public class Permission {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "permission_id")
private Integer id;
@Column(name = "permission_name")
private String name;
/** 该条记录的创建时间 */
@CreatedDate
@Column(name = "create_time")
private Date createTime;
/** 该条记录的最近更新时间 */
@LastModifiedDate
@Column(name = "update_time")
private Date updateTime;
@JoinTable(
name = "permission_role",
joinColumns = {@JoinColumn(name = "permission_id", referencedColumnName = "permission_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "role_id")}
)
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Role> roles = new HashSet<>();
}
测试代码:
@Test
public void testSave() {
Role role = new Role();
role.setName("管理员");
Role role1 = new Role();
role1.setName("部门经理");
Permission permission = new Permission();
permission.setName("上传照片");
Permission permission1 = new Permission();
permission1.setName("删除照片");
permission.getRoles().add(role);
permission.getRoles().add(role1);
permission1.getRoles().add(role);
permission1.getRoles().add(role1);
role.getPermissions().add(permission);
role.getPermissions().add(permission1);
role1.getPermissions().add(permission);
role1.getPermissions().add(permission1);
permissionRepository.save(permission);
permissionRepository.save(permission1);
roleRepository.save(role);
roleRepository.save(role1);
}
运行结果的截图:
我的语言能力较弱,若实在没讲清楚还请见谅,大家可以参考这一个博客: