java - 在微服务架构中管理与 MongoDb 的关系

标签 java mongodb microservices entity-relationship

我已经使用微服务一段时间了,总是使用关系数据库。我正在查看 MongoDb,但不确定如何处理涉及不同微服务的实体关系。下面是一个例子:

public class Employee implements Serializable {
   private String id;
   ...
}

public class Department implements Serializable {
    private String id;
    private String desc;
    private List<Employee> employees = new ArrayList<>();
    ...
}
这两个实体由两个不同的微服务管理,一对多关系由 Department 实体管理。到现在为止还挺好。
使用关系数据库(作为一种可选关系,并且一名员工可能属于多个部门),我会将其映射到 Departments 微服务中,其中一张表包含两个字段: employee_iddepartment_id 。当客户端调用 getDepartmentWithEmployees(depId) 时,该微服务将读取表并从 Employees 微服务中获取合适的员工。
但是,在 MongoDb 数据库中,据我所知,当我存储 Department 对象时,它会存储所有关联的 Employee 。这不是复制信息吗?有没有办法,也许,MongoDb 不存储有关员工的所有信息,而只存储他们的 id?或者还有其他答案?
我很确定这是一个非常基本的问题,但我对所有这些东西都很陌生。
提前致谢。

最佳答案

But, in a MongoDB database, as far as I know, when I store a Department object it stores all associated Employees. Is not that duplicating the information?


首先,上面的说法是不正确的。从 MongoDB 的角度来看,作为 BSON 提供的任何内容都按原样存储。如果您为员工提供部门,那么是的,它应该。您可以在创建部门后应用部分更新...(例如使用 $set 运算符)。但是,我认为您的问题的范围比这更广泛。
恕我直言,为数据库中的每个文档/表创建 纳米服务 不是一个好方法。特别是当服务只负责基本的 CRUD 操作时。您应该首先定义您的有界上下文、聚合根等……简而言之,在将业务需求映射到域对象之前不要尝试设计表格。我想说的是使用 DDD 原则:)
这些是我目前发现的策略。在设计微服务时,您还应该考虑每种策略的利弊。 (见底部引用。)
将关系数据库映射到 NoSQL 的一般原则
  • 1:1 关系
  • 嵌入
  • 与外键的链接

  • 1:M 关系
  • 嵌入
  • 与外键链接
  • (混合)分桶策略

  • N:M 关系
  • 双向引用
  • 单向引用


  • 1:1 关系
    1:1 关系可以通过两种方式映射;
  • 将关系嵌入为文档
  • 链接到单独集合中的文档

  • 表格:
    // Employee document
    {
       "id": 123,
       "Name":"John Doe"
    }
    
    // Address document
    {
       "City":"Ankara",
       "Street":"Genclik Street",
       "Nr":10
    }
    
    示例:嵌入 (1:1)
  • 优点: 地址可以通过一次读取操作来检索。

  • 
    {
      "id": 123,
      "Name":"John Doe",
      "Address": {
        "City":"Ankara",
        "Street":"Genclik Street",
        "Nr":10
      } 
    }
    
    示例:使用外键链接 (1:1)
    {
       "id": 763541685,  // link this
       "Name":"John Doe"
    }
    
    带有文件 key 的地址;
    {
       "employee_id": 763541685,
       "City":"Ankara",
       "Street":"Genclik street",
       "Nr":10
    }
    

    1:M 关系
    最初的:
    // Department collection
    {
      "id": 1,
      "deparment_name": "Software",
      "department_location": "Amsterdam"
    }
    
    /// Employee collection
    [
        {
          "employee_id": 46515,
          "employee_name": "John Doe"
        },
        {
          "employee_id": 81584,
          "employee_name": "John Wick"
        }
    ]
    
    示例:嵌入 (1:M)
    警告:
  • 员工名单可能很大!
  • 在写入繁重的系统中使用这种方法时要小心。 IO 负载会因内务操作(例如索引、复制等)而增加。
  • 员工分页很难!!!

  • {
      "id": 1,
      "deparment_name": "Software",
      "department_location": "Amsterdam",
      "employess": [
                       {
                         "employee_id": 46515,
                         "employee_name": "John Doe"
                       },
                       {
                         "employee_id": 81584,
                         "employee_name": "John Wick"
                       }
                   ]
    }
    
    示例:链接 (1:M)
    我们可以从员工文档中链接部门 ID。
  • 优点: 更容易分页
  • 缺点: Retrieve all employees that are belong to department X. 这个查询需要很多读操作!

  • [
        {
          "employee_id": 46515,
          "employee_name": "John Doe",
          "department_id": 1
        },
        {
          "employee_id": 81584,
          "employee_name": "John Wick",
          "department_id": 1
        }
    ]
    
    示例:分桶策略(混合 1:M)
  • 对时间序列等情况很有用。
  • 混合 = 嵌入 + 链接
  • 优势 :单次读取以一次获取 100 名员工,允许 高效分页
  • Building with Patterns: The Bucket Pattern

  • 我们将员工分成多个桶,每个桶最多 100 名员工。
    {
        "id":1,
        "Page":1,
        "Count":100,
        "Employees":[
            {
                "employee_id": 46515,
                "employee_name": "John Doe"
            },
            {
                "employee_id": 81584,
                "employee_name": "John Wick"
            }
        ]
    }
    

    N:M 关系

    To choose Two Way Embedding or One Way Embedding, the user must establish the maximum size of N and the size of M.
    For example; if N is a maximum 3 categories for a book and M is a maximum of 5,000,000 books in a category you should pick One Way Embedding.
    If N is a maximum 3 and M is a maximum of 5 then Two Way Embedding might work well. schema basics


    示例:双向引用 (N:M)
    在双向嵌入中,我们将在作者文档的 book 字段下包含 Book 外键。
    作者合集
    [
        {
           "id":1,
           "Name":"John Doe",
           "Books":[ 1, 2 ]
        },{
           "id":2,
           "Name": "John Wick",
           "Books": [ 2 ]
        }
    ]
    
    藏书:
    [
        {
           "id": 1,
           "title": "Brave New World",
           "authors": [ 1 ]
        },{
           "id":2,
           "title": "Dune",
           "authors": [ 1, 2 ]
        }
    ]
    
    示例:单向引用 (N:M)
    示例书籍和类别:这种情况是几本书属于几个类别,但几个类别可以有很多本书。
  • 优点: 优化读取性能
  • 选择将所有对类别的引用嵌入书籍中的原因是因为类别中的书籍比书籍中的类别多得多。

  • 类别
    [
      {
        "id": 1,
        "category_name": "Brave New World"
      },
      {
        "id": 2,
        "category_name": "Dune"
      }
    ]
    
    带有 Book 外键的 Categories 文档示例
    [
        {
          "id": 1,
          "title": "Brave New World",
          "categories": [ 1, 2 ],
          "authors": [ 1 ] 
        },
        {
          "id": 2,
          "title": "Dune",
          "categories": [ 1],
          "authors": [ 1, 2 ] 
        }
    ]
    
    引用
  • Case study: An algorithm for mapping the relational databases to mongodb
  • The Little MongoDB Schema Design Book
  • 6 Rules of Thumb for MongoDB Schema Design
  • 关于java - 在微服务架构中管理与 MongoDb 的关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66674061/

    相关文章:

    java - 如何避免相机在四元数旋转时翻转?

    node.js - 保存方法在 Mongoose 中不起作用

    authentication - 如何跨不同 API 对 JSON Web token (JWT) 进行身份验证?

    java - 如何不给Guava的LoadingCache添加空值?

    java - phantomjs 不能与 selenium java 一起使用

    Java 随 secret 码生成器

    java - 如何跳过 FlatFileItemReader<T> 中为空的特定列的值?

    c# - 如何使用 C# MongoDb 驱动程序更新深度嵌套数组中的字段 "type-safe"?

    database - 微服务:如何处理外键关系

    c# - 从一个位置调用多个 ASP.Net Core 微服务