【问题标题】:Problems making a many-to-many relationship work across 2 microservices using Spring Boot & Hibernate使用 Spring Boot 和 Hibernate 在 2 个微服务中建立多对多关系的问题
【发布时间】:2021-10-12 17:29:05
【问题描述】:

所以对于这个任务,我应该有 2 个微服务(任务服务和用户服务),每个都有自己的数据库。 一个任务可以分配给多个用户,但可以将多个用户分配给多个任务,因此它是多对多关系。

这两个微服务都是使用 Hibernate 的 Spring Boot 应用程序,我正在努力使任务服务中的任务和用户之间发生这种关系,因为我认为复制已经存在的用户模型不是一个好主意用户服务,交给任务服务。

此分配假定两个数据库中的用户 ID 保持一致,而无需使用外键。

对于上下文:

从 Hibernate 生成的所需实体关系图:

Task.java [任务服务]

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class Task extends BaseEntity {

    private String name, description;

    @ManyToOne
    private Lane lane;

    @OneToMany
    private List<TaskUser> users;
}

TaskUser.java [任务服务]

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@EqualsAndHashCode
public class TaskUser {

    @Id
    private Long id;

    @Column(name = "task_id")
    private Long taskId;

    @Column(name = "user_id")
    private Long userId;
 }

User.java [用户服务]

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
    @Column(unique = true)
    private String username;
}

目前,Hibernate 正在任务服务数据库中生成一个 task_user 和 task_users 表,我希望只有一个中间表而不是两个。

问题:我如何让这种多对多关系与 Hibernate 一起使用,同时使用两个不同的微服务?

【问题讨论】:

  • 您需要执行什么样的任务?您可以从用户注册、登录、任务创建、任务分配等业务需求开始。在所有这些中,用户模块不应该对任务服务有任何依赖。虽然,任务服务可能会连接到用户服务以获取用户数据。用户 db 将没有任务详细信息。只需在任务服务的任务表中为用户创建一列
  • 一个任务可以有多个用户,所以我很确定任务表上的一列不起作用。对任务服务的调用将通过 angular webapp 而不是用户服务来完成。
  • 这就是您对方法的看法。您可以拥有一个带有 alloc-id 和 task-idas pk 的 allocation-table(请参阅 embeddable ids),然后将多个用户(记录)与相同的 task-id 和新的 alloc-id 关联(自动生成)。
  • 这在 Spring Boot Hibernate 上下文中会是什么样子?

标签: java spring spring-boot hibernate jpa


【解决方案1】:

也许是一个更好的休眠映射:

Task.java [任务服务]

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class Task extends BaseEntity {

    private String name, description;

    @ManyToOne
    private Lane lane;

    @OneToMany(mappedBy="task")
    private List<TaskUser> users;
}

TaskUser.java [任务服务]

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@EqualsAndHashCode
public class TaskUser {

    @Id
    private Long id;

    @ManyToOne
    @JoinColumn(name="task_id", nullable=false)
    private Task task;

    @Column(name = "user_id")
    private Long userId;
 }

【讨论】:

  • 成功了,谢谢!
【解决方案2】:

用例:将现有任务分配给现有用户。 您可以一次将多个用户分配给 1 个任务。

后请求

/tasks/allocation/new

请求正文:

    {
      "task-id": 12345,
      "users": [
        {
          "username": "user-1",
          "user-id": 101
        },
        {
          "username": "user-2",
          "user-id": 102
        },
        {
          "username": "user-3",
          "user-id": 103
        }
      ]
    }

发布请求有一个任务和要分配给该任务的用户详细信息列表。

TaskAllocation.java
    @Data
    public class TaskAllocation{
     @jsonProperty("task-id")
     private long taskId;
     @JsonProperty("users")
     private List<Users> userList;
}
Users.java
    @Data
    public class Users{
     @jsonProperty("username")
     private String username;
     @JsonProperty("user-id")
     private Long userId;
}
休息控制器

    @PostMapping("/tasks/allocation/new")
    public CompletableFuture<ResponseEntity<?>> assignTaskToUsers(@ResponseBody @Valid TaskAllocation taskAllocation){

      // service call

    }

内部服务:
  1. 从任务数据库中获取任务(验证任务是否存在)
  2. 如果需要,从用户服务(针对每个用户)获取用户的详细信息,需要对用户服务进行异步或休息调用。任务服务没有用户的详细信息。
  3. 对于每个用户: 1.新建分配
  4. 设置任务 ID
  5. 设置用户 ID 或用户名
  6. 保存

任务已经存在

表任务分配
    --------------------------------------------------------------
    alloc-id(Pk)         task-Id(Fk)        user-id    timetamp     
    --------------------------------------------------------------
    1                     12345         101         123123123123
    2                     12345         102         123123123123
    3                     12345         103         123123123123

实体

TaskTaskAllocation 具有 1:n 关系,即 task-allocation 表由具有相同 task-id 的多条记录组成。

Task.java


    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Entity
    @Table(name = "sirf_tournament")
    public class Task extends Auditable<String> implements Serializable {
        @Id
        @GeneratedValue
        private Long taskId;

        private String taskName;
        
        // others
        
          @OneToMany(
              fetch = FetchType.LAZY,
              mappedBy = "task",
              cascade = CascadeType.ALL,
              orphanRemoval = true)
          private Collection<TaskAllocation> taskAllocation = new HashSet<>();

    }

TaskAllocation.java

    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    @Entity
    @Table(name = "sirf_tournament")
    public class TaskAllocation extends Auditable<String> implements Serializable {
        @Id
        @GeneratedValue
        private Long allocId;

        private Long userId;
        
        
        @JsonIgnore
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "taskId")
        private Task task;

        // others

    }

Usertable 等相关实体这里就不说了。任务服务没有用户信息。

如果您在将它们持久化到表之前验证每个用户(所有 id 可以在一次调用中验证,从用户服务返回无效 id)和任务 id,那将是很好的。

【讨论】:

  • 我没有看到任何 Hibernate 注释?
  • 实体和其他情况一样简单。让我更新答案。
猜你喜欢
  • 2017-11-02
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
  • 2016-01-27
  • 2013-07-27
相关资源
最近更新 更多