微服务最佳实践 – 三层数据结构

huangapple go评论92阅读模式
英文:

microservices best practice - 3 level data structure

问题

我有一个三层数据结构

level_1
ID,名称

level_2
ID,名称,ID_LEVEL1

level_3
ID,名称,ID_LEVEL2

想法是创建一个单独的微服务来管理这三个表的CRUD操作。

但是什么是最佳解决方案呢?

你想要运行一个处理一次性数据输入的API,还是要使用三个不同的API组来管理这些表呢?

我认为一次性输入数据会导致以下问题:

  • 管理CRUD事务
  • 前端复杂性
英文:

I have a three-level data structure

level_1
ID, NAME

level_2
ID, NAME, ID_LEVEL1

level_3
ID, NAME, ID_LEVEL2

The idea is to create a single microservice that manages the CRUDs on the three tables.

But what is the best solution?

Do you want to run an API that handles data entry in one go or manage tables with three different API groups?

I think entering the data in one go leads to the following problems:

  • manage the CRUD transaction
  • front end complexity

答案1

得分: 2

在你的情况下,我建议你应用组合设计模式,通常用于管理层次结构。

并且暴露一个单一的微服务来执行 CRUD 操作以管理你的层级。

在单独的表 LEVEL 中,你将有三个列:

  • id(主键)
  • name
  • parentId(可空外键,引用层级 id,在删除时级联,这意味着你将)
CREATE TABLE `level` (
  `id` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(500) NULL,
  `parentId` int unsigned NULL
);

ALTER TABLE `level`
ADD FOREIGN KEY (`parentId`) REFERENCES `level` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION

Java 类将具有:

  • 根层级的 parentId 为 null。
  • 叶子层级没有子级。
  • 使用递归方法找到层级编号,从位置 1 开始。
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.util.Set;

@Entity
@Table(name = "level")
public class Level
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private int id;

    @Column
    @Size(max = 500)
    private String name;

    @ManyToOne()
    @JoinColumn(name = "parentId")
    private Level parent;

    @OneToMany(mappedBy="parent",cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private Set<Level> children;

    public boolean isLeaf() {
        return (children == null || children.size() == 0);
    }

    public boolean isRoot() {
        return (parent == null);
    }

    public int getLevelNumber() {
        return getLevelNumber(1);
    }

    private int getLevelNumber(int currentLevel) {
        return parent == null ? currentLevel : parent.getLevelNumber(currentLevel+1) ;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Level getParent() {
        return parent;
    }

    public void setParent(Level parent) {
        this.parent = parent;
    }

    public Set<Level> getChildren() {
        return children;
    }

    public void setChildren(Set<Level> children) {
        this.children = children;
    }
}

在我看来,这是最佳且优化的解决方案。

然后我将有一个单一的仓库:

public interface LevelRepository extends JpaRepository<Level, Integer>
{

}

如果你确实需要通过鉴别器值在数据库中区分层级,那么你可以添加一个鉴别器值并管理多个 Java 对象。这将在你的 Java 项目结构中提供更多的可见性,但会使你的代码和事务管理变得复杂。

英文:

In your case, I recommand you to apply the composit design pattern, generally used to manage hierarchies.

And expose a single microservice to CRUD your levels.

In a single table LEVEL you'll have 3 columns :

  • id (primary key)
  • name
  • parentId (nullable foreign key refers to level id, on delete cascade, that's means you will )
CREATE TABLE `level` (
  `id` int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(500) NULL,
  `parentId` int unsigned NULL
);

ALTER TABLE `level`
ADD FOREIGN KEY (`parentId`) REFERENCES `level` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION

The java class will have :

  • The root level has a parentId null.
  • The leaf level has no child.
  • The level number is found using recursive method, starting at position 1.
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.util.Set;


@Entity
@Table(name = &quot;level&quot;)
public class Level
{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(updatable = false, nullable = false)
    private int id;

    @Column
    @Size(max = 500)
    private String name;

    @ManyToOne()
    @JoinColumn(name = &quot;parentId&quot;)
    private Level parent;

    @OneToMany(mappedBy=&quot;parent&quot;,cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    private Set&lt;Level&gt; children;


    public boolean isLeaf() {
        return (children == null || children.size() == 0);
    }
   
    public boolean isRoot() {
        return (parent == null);
    }
  
    public int getLevelNumber() {
        return getLevelNumber(1);
    }

    private int getLevelNumber(int currentLevel) {
        return parent == null ? currentLevel : parent.getLevelNumber(currentLevel+1) ;
    }

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public Level getParent()
    {
        return parent;
    }

    public void setParent(Level parent)
    {
        this.parent = parent;
    }

    public Set&lt;Level&gt; getChildren()
    {
        return children;
    }

    public void setChildren(Set&lt;Level&gt; children)
    {
        this.children = children;
    }
}

In my point of you, this is the best and optimized solution.

And then I will have a single repository


public interface LevelRepository extends JpaRepository&lt;Level, Integer&gt;
{

}

If you really need to distinct levels in your database by a discriminator value, then you can add a discriminator values and manage multiple java objects. It will give you more visibility in your java project structure, but will really complexify your code and the transaction management.

huangapple
  • 本文由 发表于 2020年8月18日 17:36:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63465870.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定