从 SDN+OGM 迁移到 SDN
已知的过去 SDN+OGM 迁移问题
SDN+OGM 过去几年经历了相当长的发展历程,我们深知将大型应用系统进行迁移既不轻松,也难以带来立竿见影的收益。我们在从 Spring Data Neo4j 的旧版本迁移到新版本过程中所观察到的主要问题,大致按以下顺序排列:
- 跳过了多次主要版本升级
-
虽然 Neo4j-OGM 可以独立使用,但 Spring Data Neo4j 不能。它在很大程度上依赖于 Spring Data,进而依赖于 Spring Framework 本身,这最终会影响您应用程序的大部分内容。根据应用程序的结构方式(即框架部分有多少渗透到您的业务代码中),您需要进行的适应性调整就越多。当您的应用程序中包含多个 Spring Data 模块时,情况会变得更糟;例如,如果您在同一服务层中同时访问关系型数据库和图数据库。同时更新两个对象映射框架并非一件愉快的事情。
- 依赖于通过 Spring Data 自身配置的嵌入式数据库
-
在 SDN+OGM 项目中,嵌入式数据库是通过 Neo4j-OGM 进行配置的。</p><p>假设您希望从 Neo4j 3.0 升级到 3.5,那么除非升级整个应用程序,否则无法实现。</p><p>为什么会这样呢?</p><p>由于您选择将数据库嵌入到应用程序中,就将自身绑定到了负责配置该嵌入式数据库的模块上。</p><p>若要使用另一个版本的嵌入式数据库,就必须升级负责配置它的模块,因为旧版本不支持新数据库。</p><p>由于始终存在与 Neo4j-OGM 对应的 Spring Data 版本,因此您也必须同时升级它。</p><p>然而,Spring Data 依赖于 Spring Framework,因此第一点中的论据同样适用于此。
- 不确定应包含哪些构建块
-
正确使用术语并不容易。我们在此处撰写了SDN+OGM设置的构建模块这里。也许这些组件恰好都被添加了,而您正面临大量相互冲突的依赖关系。
| 基于上述观察,我们建议您在将 SDN+OGM 迁移到 SDN 之前,确保当前应用程序仅使用 Bolt 或 HTTP 传输协议。</p><p>因此,您的应用程序及其访问层在很大程度上与数据库的版本解耦。</p><p>从这一状态出发,可考虑从 SDN+OGM 迁移到 SDN。 |
准备从 SDN+OGM Lovelace 或 SDN+OGM Moore 迁移至 SDN
| 《洛夫莱斯》(Lovelace)发布版对应 SDN 5.1.x 和 OGM 3.1.x 版本,而《摩尔》(Moore)发布版则对应 SDN 5.2.x 和 OGM 3.2.x 版本。 |
首先,您必须确保您的应用程序在服务器模式下通过 Bolt 协议与 Neo4j 进行交互,这意味着在以下三种情况中的两种情况下工作:
您正在使用嵌入式环境
您已将 org.neo4j:neo4j-ogm-embedded-driver 和 org.neo4j:neo4j 添加到您的项目中,并通过 OGM 功能启动数据库。此操作已不再受支持,您必须设置一个标准的 Neo4j 服务器(支持独立模式和集群模式)。
上述依赖项必须删除。
从嵌入式解决方案迁移可能是最困难的迁移,因为您还需要设置一个服务器。然而,这也是最能体现自身价值的一种方式:未来,您可以在不考虑应用程序框架和数据访问框架的情况下,直接升级数据库本身。
您正在使用 HTTP 传输协议
您已添加 org.neo4j:neo4j-ogm-http-driver 并配置了一个类似 user:password@localhost:7474 的 URL。该依赖项必须替换为 org.neo4j:neo4j-ogm-bolt-driver,并且您需要配置一个类似 bolt://localhost:7687 的 Bolt URL,或使用新的 neo4j:// 方案,该方案同样负责路由。
迁移
一旦您确认您的 SDN+OGM 应用程序已按预期在 Bolt 上正常运行,即可开始迁移至 SDN。
-
移除所有
org.neo4j:neo4j-ogm-*依赖项 -
通过
org.neo4j.ogm.config.Configurationbean 配置 SDN 不被支持,取而代之的是,所有驱动程序的配置均通过我们的新 Java 驱动程序Starters完成。您尤其需要调整 URL 和身份验证相关的属性,请参阅 旧版与新版属性对比
| 您无法通过 XML 配置 SDN。</p><p>如果您在 SDN+OGM 应用程序中执行了此操作,请务必了解 Spring 应用程序的注解驱动或函数式配置方法。</p><p>如今最简便的选择是 Spring Boot。</p><p>在我们已设置好Starters的前提下,除了连接 URL 和认证信息外,所有必要的配置均已为您完成。 |
# Old
spring.data.neo4j.embedded.enabled=false # No longer supported
spring.data.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
# New
spring.neo4j.uri=bolt://localhost:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret
| 那些新的属性可能会在未来再次发生变化,当SDN和驱动程序最终完全取代旧的设置时。 |
最后,添加新的依赖项,请参阅入门指南,其中包含 Gradle 和 Maven 的相关内容。
然后你就可以替换注解了:
| 旧 | 新 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
无需替换,不需要 |
|
无需替换,不需要 |
|
使用 投影;不再支持任意结果映射 |
| 若干 Neo4j-OGM 注解目前尚无对应的 Spring Data Neo4j (SDN) 注解,部分注解甚至可能永远不会存在。</p><p>随着我们支持更多功能,我们将持续更新上述列表。 |
书签管理
代码 @EnableBookmarkManagement、@UseBookmark 以及 org.springframework.data.neo4j.bookmark.BookmarkManager 接口及其唯一实现类 org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager 均已移除,不再需要。
SDN 使用书签进行所有事务,无需配置。
您也可以移除 CaffeineBookmarkManager 的 Bean 声明以及对 com.github.ben-manes.caffeine:caffeine 的依赖。
如果您确实必须这样做,可以通过遵循这些说明来禁用自动书签管理。
自动创建约束和索引
SDN 5.3 及更早版本提供了来自 Neo4j-OGM 的“自动索引管理器”。
@Index, @CompositeIndex and @Required 已被移除且未进行替换。
为什么?
我们认为,即使对于无模式数据库,创建模式也不属于领域建模的范畴。
你可能会争辩说,SDN 模型即为模式,但对此我们更倾向于采用 命令-查询分离(Command-query separation),
即我们更愿意分别定义读模型和写模型。
这些模型在编写“枯燥”的内容以及读取图结构结果时非常实用。
除此之外,某些注解及其值分别与特定的 Neo4j 版本或版本系列相关联,这使得它们难以维护。
然而,最有力的论点在于上线生产环境:尽管所有生成模式的工具在开发阶段确实很有帮助,尤其是对于那些强制执行严格模式的数据库,但在生产环境中它们往往不太友好:当您的应用程序不同版本同时运行时,您该如何处理?版本A是否应承认由较新版本B创建的索引?
我们认为最好提前掌控这一环节,并建议使用受控的数据库迁移,例如基于 Liquigraph 或 Neo4j 迁移工具。后者已在 JHipster 项目中与 SDN(Spring Data Neo4j)配合使用。这两个项目共同的特点是:它们将当前的模式版本存储在数据库中,并确保在进行更新前,现有模式符合预期。
从先前的 Neo4j-OGM 注解迁移出去会影响 @Index、@CompositeIndex 和 @Required,此处提供了一个示例:在 一个使用 Neo4j-OGM 自动索引管理器的类 中。
import org.neo4j.ogm.annotation.CompositeIndex;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.Index;
import org.neo4j.ogm.annotation.Required;
@CompositeIndex(properties = {"tagline", "released"})
public class Movie {
@Id @GeneratedValue Long id;
@Index(unique = true)
private String title;
private String description;
private String tagline;
@Required
private Integer released;
}
其注解等效于 Neo4j 4.2 版本中 Cypher 的以下模式:
CREATE CONSTRAINT movies_unique_title ON (m:Movie) ASSERT m.title IS UNIQUE;
CREATE CONSTRAINT movies_released_exists ON (m:Movie) ASSERT EXISTS (m.released);
CREATE INDEX movies_tagline_released_idx FOR (m:Movie) ON (m.tagline, m.released);
使用 @Index 而不使用 unique = true 等价于 CREATE INDEX movie_title_index FOR (m:Movie) ON (m.title)。
请注意,唯一索引已隐含了索引。