Migrating from SDN+OGM to SDN

Known issues with past SDN+OGM migrations

SDN+OGM 在过去几年中已有了一定的历史,我们理解迁移大型应用程序系统既不有趣,也无法带来直接利益。我们观察到从旧版 Spring Data Neo4j 迁移到新版 Spring Data Neo4j 时遇到的主要问题大致按下列顺序出现:

Having skipped more than one major upgrade

While Neo4j-OGM can be used stand-alone, Spring Data Neo4j cannot. It depends to large extend on the Spring Data and therefore, on the Spring Framework itself, which eventually affects large parts of your application. Depending on how the application has been structured, that is, how much the any of the framework part leaked into your business code, the more you have to adapt your application. It gets worse when you have more than one Spring Data module in your application, if you accessed a relational database in the same service layer as your graph database. Updating two object mapping frameworks is not fun.

Relying on an embedded database configured through Spring Data itself

The embedded database in a SDN+OGM project is configured by Neo4j-OGM. Say you want to upgrade from Neo4j 3.0 to 3.5, you can’t without upgrading your whole application. Why is that? As you chose to embed a database into your application, you tied yourself into the modules that configure this embedded database. To have another, embedded database version, you have to upgrade the module that configured it, because the old one does not support the new database. As there is always a Spring Data version corresponding to Neo4j-OGM, you would have to upgrade that as well. Spring Data however depends on Spring Framework and then the arguments from the first bullet apply.

Being unsure about which building blocks to include

It’s not easy to get the terms right. We wrote the building blocks of an SDN+OGM setting here. It may be so that all of them have been added by coincidence and you’re dealing with a lot of conflicting dependencies.

基于这些观察结果,我们建议您在从 SDN+OGM 切换到 SDN 之前,确保只在当前应用程序中使用 Bolt 或 http 传输。因此,您的应用程序与其应用程序的访问层在很大程度上不依赖于数据库的版本。在此状态下,考虑从 SDN+OGM 转移到 SDN。

Prepare the migration from SDN+OGM Lovelace or SDN+OGM Moore to SDN

Lovelace 发行版版本对应于 SDN 5.1.x 和 OGM 3.1.x,而 Moore 是 SDN 5.2.x 和 OGM 3.2.x。

首先,你需要确保你的应用程序通过 Bolt 协议针对服务器模式的 Neo4j 运行,这意味着在三种情况下中的两种情况下都需要展开工作:

You’re on embedded

你已向项目添加了 org.neo4j:neo4j-ogm-embedded-driverorg.neo4j:neo4j,并通过 OGM 设施启动了数据库。这不再受支持,你需要设置标准 Neo4j 服务器(支持独立和集群)。

必须移除上述依赖关系。

从嵌入式解决方案迁移可能是最棘手的迁移,因为你也需要设置服务器。但从长远来看,它会给你带来很多好处:将来,你将能够在无需考虑应用程序框架及数据访问框架的情况下升级数据库本身。

You’re using the HTTP transport

你已添加了 org.neo4j:neo4j-ogm-http-driver,并配置了一个类似于 http://user:password@localhost:7474 的 URL。此依赖关系必须替换为 org.neo4j:neo4j-ogm-bolt-driver,你需要配置一个类似于 bolt://localhost:7687 的 Bolt URL,或者使用新的 neo4j:// 架构,它还负责路由。

You’re already using Bolt indirectly

默认的 SDN+OGM 项目使用 org.neo4j:neo4j-ogm-bolt-driver,因此间接使用了纯 Java 驱动程序。你可以保留现有的 URL。

Migrating

一旦确保 SDN+OGM 应用程序按预期通过 Bolt 运行,你就可以开始迁移到 SDN。

  • Remove all org.neo4j:neo4j-ogm-* dependencies

  • 不支持通过 org.neo4j.ogm.config.Configuration Bean 配置 SDN,相反,驱动程序的所有配置都通过我们新的 Java 驱动程序启动器进行。您将特别需要为 URL 和身份验证调整属性,请参阅 [migrating-auth]

您无法通过 XML 配置 SDN。如果您使用 SDN+OGM 应用程序执行此操作,请务必了解 Spring 应用程序的注释驱动或功能配置。当今最简单的方法是 Spring Boot。有了我们的启动程序,除了连接 URL 和身份验证之外的所有必需部分都已为您配置。

Old and new properties compared
# 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 和驱动程序最终完全替换旧设置时,这些新属性将来可能再次发生更改。

最后,添加新依赖项,请参阅 Getting started,适用于 Gradle 和 Maven。

然后,你就可以替换注解:

Old New

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

No replacement, not needed

org.springframework.data.neo4j.annotation.UseBookmark

No replacement, not needed

org.springframework.data.neo4j.annotation.QueryResult

使用 projections;不再支持任意结果映射

几个 Neo4j-OGM 注释尚未在 SDN 中具有相应的注释,有些永远不会有。当我们支持其他功能时,我们将添加到以上列表中。

Bookmark management

@EnableBookmarkManagement@UseBookmark 以及 org.springframework.data.neo4j.bookmark.BookmarkManager 接口及其唯一实现 org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager 都已消失且不再需要。

SDN 对所有事务都使用书签,无需配置。你可以删除 CaffeineBookmarkManager 的 Bean 声明以及对 com.github.ben-manes.caffeine:caffeine 的依赖。

如果您确实必须这样做,则可以通过遵循 these instructions来禁用自动书签管理。

Automatic creation of constraints and indexes

SDN 5.3 及更早版本提供了 Neo4j-OGM 的“自动索引管理器”。

@Index@CompositeIndex@Required 已在未替换的情况下删除了。为什么?我们认为创建架构(即使是无架构的数据库)不属于域建模。您可以认为 SDN 模型是架构,但我们甚至会回答说我们更喜欢 Command-query separation,这意味着我们宁愿定义单独的读写模型。对于编写“枯燥”的事物和读取图形形状的答案,它们非常有用。

除此之外,其中一些批注及其值分别与特定的 Neo4j 版本或发行版相关联,这使得它们难以维护。

然而,最好的论点即将投入生产:虽然所有生成架构的工具在开发过程中肯定有用,对于强制执行严格方案的数据库来说更是如此,但它们在生产中往往不太好用:如何同时处理不同版本的应用程序?版本 A 断言由较新版本 B 创建的索引?

我们认为最好在前期控制这一点,并建议使用基于像 LiquigraphNeo4j migrations 这样的工具的受控数据库迁移。后者已经与 JHipster 项目中的 SDN 一起使用。这两个项目的共同点是,它们将架构的当前版本存储在数据库中,并确保在更新内容之前架构符合预期。

从以前的 Neo4j-OGM 批注迁移会影响 @Index@CompositeIndex@Required,并且 [indexed.class] 中给出了一个示例:

A class making use of Neo4j-OGM automatic index manager
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):

Example Cypher based migration
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)。请注意,唯一索引已经暗示了一个索引。