【发布时间】:2018-12-25 03:47:51
【问题描述】:
在代码中,我尝试在非拥有方以一对多关系使用@Interleaved 来获取子列表。任何人都可以帮助解决以下问题:
- 如何实现双向关系,例如从孩子那里获得一对一、一对多关系的父母
- 关于多对多关系,实现它的最佳实践是什么以及如何实现它的双向关系。
非常感谢。
【问题讨论】:
标签: spring google-cloud-platform google-cloud-spanner
在代码中,我尝试在非拥有方以一对多关系使用@Interleaved 来获取子列表。任何人都可以帮助解决以下问题:
非常感谢。
【问题讨论】:
标签: spring google-cloud-platform google-cloud-spanner
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';
在读写事务中运行这两个语句将确保Referenced和Referencing表之间的PK-FK关系在插入时始终保持不变。您可能必须在应用程序逻辑中类似地修改更新请求/SQL 更新语句,以强制执行更新的 PK-FK 约束。
【讨论】:
对于一对多关系,当使用交错表时,子行的主键已经包含其父行的主键,所以很容易得到父行。
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
);
您的应用程序将负责保持映射表的引用完整性 - 当 table1 或 table2 中的行被删除时删除映射行
如果您想使用交错表,那么如果您的应用程序需要执行双向查找,您可能必须创建 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(反之亦然)。
【讨论】: