从 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 URL,例如 bolt://localhost:7687
,或者使用新的 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://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 注解在 SDN 中还没有对应的注解,有些永远不会有。随着我们支持更多功能,我们将添加到上面的列表中。 |
Bookmark 管理
@EnableBookmarkManagement
和 @UseBookmark
,以及 org.springframework.data.neo4j.bookmark.BookmarkManager
接口及其唯一实现 org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager
都已移除,不再需要。
SDN 在所有事务中都使用 bookmarks,无需配置。您可以移除 CaffeineBookmarkManager
的 Bean 声明以及对 com.github.ben-manes.caffeine:caffeine
的依赖。
如果绝对必要,您可以按照这些说明禁用自动 bookmark 管理。
自动创建约束和索引
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)
。请注意,唯一索引本身就隐含着索引。