Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
675 views
in Technique[技术] by (71.8m points)

spring boot data jpa EntityExistsException

我用spring data jpa 写了两个多对多关系的实体Role和Permission,想在关系表里添加一些额外的字段,参考了这篇文章:JAP多对多最佳实践
一下时代码:
Role 实体类

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class Role {

    @Id
    @GeneratedValue(generator = "jpa-uuid")
    private String id;

    @JsonIgnore @ToString.Exclude
    @OneToMany(mappedBy = "role",cascade = CascadeType.ALL,orphanRemoval = false,fetch = FetchType.EAGER)
    private Set<RolePermission> role_permission;

    public void addPermission(Permission permission){
        RolePermission rolePermission  = new RolePermission(this,permission);
        role_permission.add(rolePermission);
        permission.getRole_permission().add(rolePermission);
    }
    public void removePermission(Permission permission){
        for(Iterator<RolePermission> iterator = role_permission.iterator();iterator.hasNext();){
            RolePermission rolePermission = iterator.next();
            if(rolePermission.getRole().equals(this) && rolePermission.getPermission().equals(permission)){
                iterator.remove();
                rolePermission.getRole().role_permission.remove(rolePermission);
                rolePermission.setRole(null);
                rolePermission.setPermission(null);
            }
        }
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Role role = (Role) o;
        return Objects.equals(id, role.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Permission 实体类

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@GenericGenerator(name = "jpa-uuid", strategy = "uuid")
public class Permission {
    @Id
    @GeneratedValue(generator = "jpa-uuid")
    private String id;

    @JsonIgnore @ToString.Exclude
    @OneToMany(mappedBy = "permission",cascade = CascadeType.ALL,orphanRemoval = true,fetch = FetchType.EAGER)
    private Set<RolePermission> role_permission;

    public void addRole(Role role){
        RolePermission rolePermission  = new RolePermission(role,this);
        role_permission.add(rolePermission);
        role.getRole_permission().add(rolePermission);
    }
    public void removeRole(Role role){
        for(Iterator<RolePermission> iterator = role_permission.iterator(); iterator.hasNext();){
            RolePermission rolePermission = iterator.next();
            if(rolePermission.getRole().equals(role) && rolePermission.getPermission().equals(this)){
                iterator.remove();
                rolePermission.getRole().getRole_permission().remove(rolePermission);
                rolePermission.setRole(null);
                rolePermission.setPermission(null);
            }
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Permission that = (Permission) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Role Permission 主键类


@Embeddable
@Setter
@Getter
@NoArgsConstructor
public class RolePermissionKey implements Serializable {
    private static final long serialVersionUID = 4686642987484483168L;
    @Column(name = "role_id")
    private String role_id;
    @Column(name = "permission_id")
    private String permission_id;

    public RolePermissionKey(String roleId, String permissionId) {
        this.role_id=roleId;
        this.permission_id=permissionId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RolePermissionKey that = (RolePermissionKey) o;
        return role_id.equals(that.role_id) &&
                permission_id.equals(that.permission_id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(role_id, permission_id);
    }
}

带着额外字段的实体表

@Entity
@Setter
@Getter
@NoArgsConstructor
public class RolePermission implements Serializable {
    private static final long serialVersionUID = 8274025418699729303L;

    @EmbeddedId
    RolePermissionKey id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("role_id")
    Role role;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("permission_id")
    Permission permission;

    Date create_date  =new Date();


    public RolePermission(Role role,Permission permission) {
        this.role=role;
        this.permission=permission;
        this.id = new RolePermissionKey(role.getId(),permission.getId());
        this.create_date=new Date();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RolePermission that = (RolePermission) o;
        return Objects.equals(role, that.role) &&
                Objects.equals(permission, that.permission);
    }

    @Override
    public int hashCode() {
        return Objects.hash(role, permission);
    }
}

测试代码

        Role role5 = roleRepository.findByTitle("Role5");
        Permission permission6 = permissionRepository.findByTitle("Permission6");
        role5.get().addPermission(permission6);
        permission6.addRole(role5);
        roleRepository.save(role5);
        permissionRepository.save(permission6);

现在的情况是我将测试用的代码片段贴在了4各不同的地方,有的地方能执行成功得到预期结果,有的地方会抛出异常,具体如下:
1. ApplicationRunner 的实现类;boot启动时初始化数据,正常执行
2. 一个测试类 @SpringBootTest;正常执行
3. 一个 @Controller 类 ;抛异常
4. 一个 @Service 类;抛异常
异常信息:2020-05-05 09:11:35.952 WARN 17000 --- [nio-8080-exec-1] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session : [com.xxx.model.authentication.RolePermission#com.xxx.model.authentication.RolePermissionKey@9e2c8771]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.xxx.model.authentication.RolePermission#com.xxx.model.authentication.RolePermissionKey@9e2c8771]]
不清楚为什么会有的地方执行成功,有的地方会抛出异常。
两个实体类中保存关系的集合用的时set,并且重写了两个实体的equals()和hashcode()方法,关系集合中不会出现重复ID的对象。
测试代码中有两个save()的动作,注释掉其中任何一个依然会报异常。麻烦大家 帮忙看看,谢谢了。


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...