从 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 配置。假设您想从 Neo4j 3.0 升级到 3.5,如果不升级整个应用程序,这是不可能的。为什么?因为您选择将数据库嵌入到您的应用程序中,所以您将自己绑定到了配置此嵌入式数据库的模块中。要使用另一个嵌入式数据库版本,您必须升级配置它的模块,因为旧的模块不支持新的数据库。由于总是存在与 Neo4j-OGM 对应的 Spring Data 版本,因此您也必须升级它。但是,Spring Data 依赖于 Spring Framework,然后第一个要点中的论点就适用了。
- 不确定要包含哪些构建块
-
正确理解这些术语并不容易。我们在这里编写了SDN+OGM 设置的构建块。可能是所有这些构建块都是偶然添加的,您正在处理许多冲突的依赖项。
基于这些观察结果,我们建议在从 SDN+OGM 切换到 SDN 之前,确保您当前的应用程序仅使用 Bolt 或 http 传输。这样,您的应用程序和应用程序的访问层在很大程度上独立于数据库的版本。从这种状态开始,考虑从 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://127.0.0.1:7687` 的 Bolt URL,或者使用新的 `neo4j://` 方案,该方案也能处理路由。
迁移
一旦您确保您的 SDN+OGM 应用程序按预期通过 Bolt 运行,您就可以开始迁移到 SDN 了。
-
删除所有 `org.neo4j:neo4j-ogm-*` 依赖项
-
通过 `org.neo4j.ogm.config.Configuration` bean 配置 SDN 不受支持,相反,驱动程序的所有配置都通过我们新的 Java 驱动程序启动器进行。您尤其必须调整 url 和身份验证的属性,请参见旧属性和新属性的比较
您无法通过 XML 配置 SDN。如果您在 SDN+OGM 应用程序中这样做,请确保学习有关 Spring 应用程序的基于注解或功能的配置。如今最简单的选择是 Spring Boot。有了我们的启动器,除了连接 URL 和身份验证之外,所有必要的部分都已为您配置好。 |
# Old
spring.data.neo4j.embedded.enabled=false # No longer supported
spring.data.neo4j.uri=bolt://127.0.0.1:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
# New
spring.neo4j.uri=bolt://127.0.0.1:7687
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=secret
当 SDN 和驱动程序最终完全取代旧设置时,这些新属性将来可能会再次更改。 |
最后,添加新的依赖项,有关 Gradle 和 Maven 的信息,请参见入门。
然后,您可以准备替换注释了
旧的 | 新的 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
无需替换,不需要 |
|
无需替换,不需要 |
|
使用投影;不再支持任意结果映射 |
一些 Neo4j-OGM 注解在 SDN 中还没有对应的注解,有些注解将永远不会有。随着我们支持更多功能,我们将添加到上面的列表中。 |
书签管理
@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
和 @Required
已被移除,没有替代品。为什么?我们认为创建模式——即使对于无模式数据库——也不是领域建模的一部分。您可以认为 SDN 模型就是模式,但我们会回答说我们甚至更喜欢命令查询分离,这意味着我们宁愿定义单独的读写模型。这些对于编写“枯燥”的事情和读取图形形状的答案非常方便。
除此之外,某些注解及其值与特定的 Neo4j 版本或发行版绑定,这使得它们难以维护。
然而,最好的论据是投入生产:虽然所有生成模式的工具在开发过程中确实很有帮助,尤其是在强制使用严格模式的数据库中,但它们在生产环境中往往不太好用:您如何处理同时运行的不同应用程序版本?版本 A 断言由较新版本 B 创建的索引?
我们认为最好提前控制这一点,并建议使用基于诸如Liquigraph或Neo4j migrations之类的工具的受控数据库迁移。后者已在 JHipster 项目中与 SDN 一起使用。这两个项目都有一个共同点,它们将模式的当前版本存储在数据库中,并在更新内容之前确保模式符合预期。
从之前的 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;
}
它的注解等效于以下 Cypher 模式(截至 Neo4j 4.2)
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);
不使用 unique = true
使用 @Index
等效于 CREATE INDEX movie_title_index FOR (m:Movie) ON (m.title)
。请注意,唯一索引已经隐含了一个索引。