从 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 框架,因此第一点中的论点也同样适用。
不确定要包含哪些构建模块
正确地理解这些术语并不容易。我们在这里这里编写了 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
并配置了一个 URL,例如 [user:password@localhost:7474](http://user:password@localhost:7474)
。该依赖需要替换为 org.neo4j:neo4j-ogm-bolt-driver
,并且你需要配置一个 Bolt URL,例如 bolt://localhost:7687
或使用新的 neo4j://
方案,该方案也负责路由。
你已经在间接使用 Bolt
默认的 SDN+OGM 项目使用 org.neo4j:neo4j-ogm-bolt-driver
,因此间接使用了纯 Java 驱动。你可以保留现有的 URL。
迁移
在确认您的 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://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 的操作步骤。
然后你就可以开始替换注释了:
旧版本 | 新版本 |
---|---|
org.neo4j.ogm.annotation.NodeEntity | org.springframework.data.neo4j.core.schema.Node |
org.neo4j.ogm.annotation.GeneratedValue | org.springframework.data.neo4j.core.schema.GeneratedValue |
org.neo4j.ogm.annotation.Id | org.springframework.data.neo4j.core.schema.Id |
org.neo4j.ogm.annotation.Property | org.springframework.data.neo4j.core.schema.Property |
org.neo4j.ogm.annotation.Relationship | org.springframework.data.neo4j.core.schema.Relationship |
org.springframework.data.neo4j.annotation.EnableBookmarkManagement | 无替代,不再需要 |
org.springframework.data.neo4j.annotation.UseBookmark | 无替代,不再需要 |
org.springframework.data.neo4j.annotation.QueryResult | 使用投影;不再支持任意结果映射 |
一些 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);
使用 @Index
而不带 unique = true
等同于 CREATE INDEX movie_title_index FOR (m:Movie) ON (m.title)
。需要注意的是,唯一索引已经隐含了索引的存在。