【问题标题】:How to implement bidirectional relationship in Spring Spanner?如何在 Spring Spanner 中实现双向关系?
【发布时间】:2018-12-25 03:47:51
【问题描述】:

在代码中,我尝试在非拥有方以一对多关系使用@Interleaved 来获取子列表。任何人都可以帮助解决以下问题:

  1. 如何实现双向关系,例如从孩子那里获得一对一、一对多关系的父母
  2. 关于多对多关系,实现它的最佳实践是什么以及如何实现它的双向关系。

非常感谢。

【问题讨论】:

    标签: spring google-cloud-platform google-cloud-spanner


    【解决方案1】:

    Cloud Spanner 目前不提供在非交错表之间强制执行外键约束的方法。您必须在应用程序逻辑中强制执行此类约束。您可以使用DML statements in Cloud Spanner(具有在 Cloud Spanner 事务中读取您的写入的能力)在插入时通过插入到您的表中来强制执行这些约束,如下所示:

    INSERT INTO Referenced(key1,value1) VALUES ('Referenced','Value1');
    INSERT INTO Referencing(key2, value2, key1) 
    SELECT 'Referencing', 'Value2', key1 FROM Referenced WHERE
    key1 = 'Referenced'; 
    

    在读写事务中运行这两个语句将确保ReferencedReferencing表之间的PK-FK关系在插入时始终保持不变。您可能必须在应用程序逻辑中类似地修改更新请求/SQL 更新语句,以强制执行更新的 PK-FK 约束。

    【讨论】:

    • 感谢@adi 分享信息。但是,我想知道的是: 1. 如何从拥有实体(如 JPA)中获得 1-n、1-1 关系中的非拥有实体(从 n 侧到 1 侧)。 2.如何实现m-n最好考虑table/interleave的方式。
    【解决方案2】:

    对于一对多关系,当使用交错表时,子行的主键已经包含其父行的主键,所以很容易得到父行。

    CREATE TABLE parent (
        parent_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (parent_key);
    
    CREATE TABLE child (
        parent_key INT64 NOT NULL,
        child_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (parent_key, child_key),
    INTERLEAVE IN PARENT parent ON DELETE CASCADE;
    

    如果由于某种原因您没有父项的键,而只有子项的键,那么为了提高效率,您需要为反向查找创建一个索引:

    CREATE INDEX child_to_parent_index 
    ON child (
        child_key
    );
    

    并在执行父查询时强制使用该索引:

    SELECT 
        p.* 
    FROM 
        parent as p 
    JOIN 
        child@{FORCE_INDEX=child_by_id_index} AS c ON p.parent_key = c.parent_key 
    WHERE 
        c.child_key = @CHILD_KEY_VALUE;
    

    多对多关系必须使用将table1-key 链接到table2-key 的“映射”表来实现。 您还需要一个顶级索引来获得高效的反向查找,并在查询中使用上述FORCE_INDEX 指令。

    正如@adi 提到的,外键约束必须由应用程序强制执行。

    CREATE TABLE table1 (
        table1_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (table1_key);
    
    CREATE TABLE table2 (
        table2_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (table2_key);
    
    CREATE TABLE table1_table2_map (
        table1_key INT64 NOT NULL,
        table2_key INT64 NOT NULL,
    ) PRIMARY KEY (table1_key, table2_key);
    
    CREATE INDEX table2_table1_map_index 
    ON table1_table2_map (
        table2_key
    ) STORING (
        table1_key
    );
    

    您的应用程序将负责保持映射表的引用完整性 - 当 table1table2 中的行被删除时删除映射行

    如果您想使用交错表,那么如果您的应用程序需要执行双向查找,您可能必须创建 2 个映射表 - 作为每个父级的子级,以便从两个方向查找映射同样有效.

    CREATE TABLE table1 (
        table1_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (table1_key);
    
    CREATE TABLE table2 (
        table2_key INT64 NOT NULL,
        ...
    ) PRIMARY KEY (table2_key);
    
    CREATE TABLE table1_table2_map (
        table1_key INT64 NOT NULL,
        table2_key INT64 NOT NULL,
    ) PRIMARY KEY (table1_key, table2_key),
    INTERLEAVE IN PARENT table1 ON DELETE CASCADE;
    
    CREATE TABLE table2_table1_map (
        table2_key INT64 NOT NULL,
        table1_key INT64 NOT NULL,
    ) PRIMARY KEY (table2_key, table1_key),
    INTERLEAVE IN PARENT table2 ON DELETE CASCADE; 
    

    请注意,应用程序需要保持两个这些映射表都是最新的——即,当从 table1 中删除一行时,应用程序必须获取引用的 table2_key 值并删除映射来自table2_table1_map(反之亦然)。

    【讨论】:

    • 感谢@RedPandaCurios 的长篇回答。实际上,我正在寻找带有注释(@ManyToOne)的 JPA 中的内置函数,这样我就不必发出查询来查找父级,但似乎 Spring Spanner 还不支持它。 Anw,其他提到的信息都很好。谢谢
    猜你喜欢
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-10
    • 2021-05-19
    相关资源
    最近更新 更多