Migrating from SDN+OGM to SDN
Known issues with past SDN+OGM migrations
SDN+OGM 在过去几年中已有了一定的历史,我们理解迁移大型应用程序系统既不有趣,也无法带来直接利益。我们观察到从旧版 Spring Data Neo4j 迁移到新版 Spring Data Neo4j 时遇到的主要问题大致按下列顺序出现:
SDN+OGM has had quite a history over the years and we understand that migrating big application systems is neither fun nor something that provides immediate profit. The main issues we observed when migrating from older versions of Spring Data Neo4j to newer ones are roughly in order the following:
- 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。 |
Backed by those observations, we recommend to make sure you’re using only the Bolt or http transport in your current application before switching from SDN+OGM to SDN. Thus, your application and the access layer of your application is to a large extent independent of the database’s version. From that state, consider moving from SDN+OGM to 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。 |
The Lovelace release train corresponds to SDN 5.1.x and OGM 3.1.x, while the Moore is SDN 5.2.x and OGM 3.2.x. |
首先,你需要确保你的应用程序通过 Bolt 协议针对服务器模式的 Neo4j 运行,这意味着在三种情况下中的两种情况下都需要展开工作:
First, you must make sure that your application runs against Neo4j in server mode over the Bolt protocol, which means work in two of three cases:
You’re on embedded
你已向项目添加了 org.neo4j:neo4j-ogm-embedded-driver
和 org.neo4j:neo4j
,并通过 OGM 设施启动了数据库。这不再受支持,你需要设置标准 Neo4j 服务器(支持独立和集群)。
You have added org.neo4j:neo4j-ogm-embedded-driver
and org.neo4j:neo4j
to you project and starting the database via OGM facilities.
This is no longer supported and you have to set up a standard Neo4j server (both standalone and cluster are supported).
必须移除上述依赖关系。
The above dependencies have to be removed.
从嵌入式解决方案迁移可能是最棘手的迁移,因为你也需要设置服务器。但从长远来看,它会给你带来很多好处:将来,你将能够在无需考虑应用程序框架及数据访问框架的情况下升级数据库本身。
Migrating from the embedded solution is probably the toughest migration, as you need to set up a server, too. It is however the one that gives you much value in itself: In the future, you will be able to upgrade the database itself without having to consider your application framework, and your data access framework as well.
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 have added org.neo4j:neo4j-ogm-http-driver
and configured an url like http://user:password@localhost:7474
.
The dependency has to be replaced with org.neo4j:neo4j-ogm-bolt-driver
and you need to configure a Bolt url like bolt://localhost:7687
or use the new neo4j://
scheme, which takes care of routing, too.
Migrating
一旦确保 SDN+OGM 应用程序按预期通过 Bolt 运行,你就可以开始迁移到 SDN。
Once you have made sure, that your SDN+OGM application works over Bolt as expected, you can start migrating to SDN.
-
Remove all
org.neo4j:neo4j-ogm-*
dependencies -
Configuring SDN through a
org.neo4j.ogm.config.Configuration
bean is not supported, instead of, all configuration of the driver goes through our new Java driver starter. You will especially have to adapt the properties for the url and authentication, see [migrating-auth]
您无法通过 XML 配置 SDN。如果您使用 SDN+OGM 应用程序执行此操作,请务必了解 Spring 应用程序的注释驱动或功能配置。当今最简单的方法是 Spring Boot。有了我们的启动程序,除了连接 URL 和身份验证之外的所有必需部分都已为您配置。 |
You cannot configure SDN through XML. In case you did this with your SDN+OGM application, make sure you learn about annotation-driven or functional configuration of Spring Applications. The easiest choice these days is Spring Boot. With our starter in place, all the necessary bits apart from the connection URL and the authentication is already configured for you. |
# 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 和驱动程序最终完全替换旧设置时,这些新属性将来可能再次发生更改。
Those new properties might change in the future again when SDN and the driver eventually fully replace the old setup.
最后,添加新依赖项,请参阅 Getting started,适用于 Gradle 和 Maven。
And finally, add the new dependency, see Getting started for both Gradle and Maven.
然后,你就可以替换注解:
You’re then ready to replace annotations:
Old | New |
---|---|
|
|
|
|
|
|
|
|
|
|
|
No replacement, not needed |
|
No replacement, not needed |
|
Use projections; arbitrary result mapping not supported anymore |
几个 Neo4j-OGM 注释尚未在 SDN 中具有相应的注释,有些永远不会有。当我们支持其他功能时,我们将添加到以上列表中。 |
Several Neo4j-OGM annotations have not yet a corresponding annotation in SDN, some will never have. We will add to the list above as we support additional features. |
Bookmark management
@EnableBookmarkManagement
和 @UseBookmark
以及 org.springframework.data.neo4j.bookmark.BookmarkManager
接口及其唯一实现 org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager
都已消失且不再需要。
Both @EnableBookmarkManagement
and @UseBookmark
as well as the org.springframework.data.neo4j.bookmark.BookmarkManager
interface and its only implementation org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager
are gone and are not needed anymore.
SDN 对所有事务都使用书签,无需配置。你可以删除 CaffeineBookmarkManager
的 Bean 声明以及对 com.github.ben-manes.caffeine:caffeine
的依赖。
SDN uses bookmarks for all transactions, without configuration.
You can remove the bean declaration of CaffeineBookmarkManager
as well as the dependency to com.github.ben-manes.caffeine:caffeine
.
如果您确实必须这样做,则可以通过遵循 these instructions来禁用自动书签管理。
If you absolutely must, you can disable the automatic bookmark management by following these instructions.
Automatic creation of constraints and indexes
SDN 5.3 及更早版本提供了 Neo4j-OGM 的“自动索引管理器”。
SDN 5.3 and prior provided the "Automatic index manager" from Neo4j-OGM.
@Index
、@CompositeIndex
和 @Required
已在未替换的情况下删除了。为什么?我们认为创建架构(即使是无架构的数据库)不属于域建模。您可以认为 SDN 模型是架构,但我们甚至会回答说我们更喜欢 Command-query separation,这意味着我们宁愿定义单独的读写模型。对于编写“枯燥”的事物和读取图形形状的答案,它们非常有用。
@Index
, @CompositeIndex
and @Required
have been removed without replacement.
Why?
We think that creating the schema - even for a schemaless database - is not part of the domain modelling.
You could argue that an SDN model is the schema, but than we would answer that we even prefer a Command-query separation,
meaning that we would rather define separate read and write models.
Those come in very handy for writing "boring" things and reading graph-shaped answers.
除此之外,其中一些批注及其值分别与特定的 Neo4j 版本或发行版相关联,这使得它们难以维护。
Apart from that, some of those annotations respectively their values are tied to specific Neo4j editions or versions, which makes them hard to maintain.
然而,最好的论点即将投入生产:虽然所有生成架构的工具在开发过程中肯定有用,对于强制执行严格方案的数据库来说更是如此,但它们在生产中往往不太好用:如何同时处理不同版本的应用程序?版本 A 断言由较新版本 B 创建的索引?
The best argument however is going to production: While all tools that generate a schema are indeed helpful during development, even more so with databases that enforces a strict scheme, they tend to be not so nice in production: How do you handle different versions of your application running at the same time? Version A asserting the indexes that have been created by a newer version B?
我们认为最好在前期控制这一点,并建议使用基于像 Liquigraph 或 Neo4j migrations 这样的工具的受控数据库迁移。后者已经与 JHipster 项目中的 SDN 一起使用。这两个项目的共同点是,它们将架构的当前版本存储在数据库中,并确保在更新内容之前架构符合预期。
We think it’s better to take control about this upfront and recommend using controlled database migrations, based on a tool like Liquigraph or Neo4j migrations. The latter has been seen in use with SDN inside the JHipster project. Both projects have in common that they store the current version of the schema within the database and make sure that a schema matches expectations before things are being updated.
从以前的 Neo4j-OGM 批注迁移会影响 @Index
、@CompositeIndex
和 @Required
,并且 [indexed.class] 中给出了一个示例:
Migrating off from previous Neo4j-OGM annotations affects @Index
, @CompositeIndex
and @Required
and an example for those is given here in [indexed.class]:
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):
It’s annotations are equivalent to the following scheme in Cypher (as of 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)
。请注意,唯一索引已经暗示了一个索引。
Using @Index
without unique = true
is equivalent to CREATE INDEX movie_title_index FOR (m:Movie) ON (m.title)
.
Note that a unique index already implies an index.