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

    }

运行结果的截图:

JPA - 双向多对多映射

JPA - 双向多对多映射

我的语言能力较弱,若实在没讲清楚还请见谅,大家可以参考这一个博客:

https://blog.****.net/J080624/article/details/78776560