无法将两个 Neo4j 实例与 Spring boot/Spring 数据 neo4j 一起使用
Unable to use two Neo4j Instances with Spring boot/Spring data neo4j
预期行为
Trying to use two Neo4j instances with Spring boot and Spring data Neo4j
当前行为
Able to use only one Neo4j instances. Unable to use two repositories.
重现步骤(针对错误)
1. Run two Neo4j Instances
2. Create Data source configuration for both Neo4j Instances using spring boot.
3. Use Repository to access the Node entity
4. It will throw error
上下文
假设我是 运行 一家图书馆,正在向其他用户出租书籍。如果用户从我这里租书,相同的节点详细信息将出现在他们的存储库中,我将允许他们通过我的应用程序编辑节点实体(如添加关键字、添加关于书籍的亮点等)
因此在两个存储库中,节点详细信息将相同。
下面是应用程序。两个 Neo4j 存储库的属性详细信息。
我的 Neo4j 存储库详细信息
spring.data.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j
租用用户的 Neo4j 存储库详细信息
(通过 http 访问,在其他机器上是 运行)
rental.data.neo4j.uri=bolt://...:7687
rental.data.neo4j.username=neo4j
rental.data.neo4j.password=neo4j
以下是租赁用户的 Neo4j 配置:
@configuration
@EnableNeo4jRepositories(basePackages = "com.metadata.dao.rentallibrary", sessionFactoryRef = "rentalSessionFactory", transactionManagerRef = "rentalUsertransactionManager")
@EnableTransactionManagement
@EntityScan("com.metadata.dao")
public class rentalUserNeo4jConfiguration {
@Value("${rental.data.neo4j.uri}")
private String url;
@Value("${rental.data.neo4j.username}")
private String userName;
@Value("${rental.data.neo4j.password}")
private String password;
@Bean(name = "rentalSessionFactory")
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), "com.metadata.dao.rentallibrary.entity");
}
@Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)// "
.credentials(userName, password)
.build();
return configuration;
}
@Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
下面是我的图书馆的 Neo4j 配置细节:
@configuration
@EnableNeo4jRepositories(basePackages = "com.metadata.dao.mylibrary", sessionFactoryRef = "myUserSessionFactory", transactionManagerRef = "myUserTransactionManager")
@EnableTransactionManagement
public class MyUserNeo4jConfiguration {
@Value("${spring.data.neo4j.uri}")
private String url;
@Value("${spring.data.neo4j.username}")
private String userName;
@Value("${spring.data.neo4j.password}")
private String password;
@Bean(name = "myUserSessionFactory")
@Primary
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), "com.metadata.dao.mylibrary.entity");
}
@Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)
.credentials(userName, password)
.build();
return configuration;
}
@Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
我正在尝试使用会话工厂(通过限定符)访问两个存储库,它工作正常。但是我正在尝试通过我面临问题的存储库访问数据。
**Accessing through SessionFactory :**
@Autowired
@Qualifier(value = "myUserSessionFactory")
SessionFactory myUserSessionFactory;
@Autowired
@Qualifier(value = "rentalUserSessionFactory")
SessionFactory rentalUserSessionFactory;
以下是错误的详细信息,我在尝试通过以下方式访问数据时得到:
java.lang.IllegalArgumentException: Class class com.metadata.dao.Book is not a valid entity class. Please check the entity mapping.
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:88) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:40) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:469) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at org.springframework.data.neo4j.transaction.SharedSessionCreator$SharedSessionInvocationHandler.invoke(SharedSessionCreator.java:131) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at com.sun.proxy.$Proxy81.save(Unknown Source) ~[na:na]
org.neo4j.ogm.exception.core.TransactionManagerException: Transaction is not current for this thread
at org.neo4j.ogm.session.transaction.DefaultTransactionManager.rollback(DefaultTransactionManager.java:86) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.rollback(AbstractTransaction.java:65) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.neo4j.ogm.drivers.bolt.transaction.BoltTransaction.rollback(BoltTransaction.java:61) ~[neo4j-ogm-bolt-driver-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.close(AbstractTransaction.java:144) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.springframework.data.neo4j.transaction.Neo4jTransactionManager.doCleanupAfterCompletion(Neo4jTransactionManager.java:379) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
dao.mylibrary.entity 中的节点实体名称:书籍
dao.rentallibrary.entity 中的节点实体名称:RentedBook
请告诉我为什么在使用 Neo4j 存储库时会出现此问题?我们不能将两个 Neo4j 存储库与 Spring data neo4j & Spring boot 一起使用吗?还是我做错了什么?
我的环境
OGM Version used: 3.1.0
Java Version used: 1.8
Neo4J Version used:3.2.3
Bolt Driver Version used (if applicable): 3.1.0
Operating System and Version: Windows
Please let me know if you need any additional information.
更新 这已在 Spring Data Neo4j Lovelace RC1 中解决,我们写了一个小指南:https://michael-simons.github.io/neo4j-sdn-ogm-tips/using_multiple_session_factories
感谢您将此作为 GitHub 问题提交 #498。
似乎当前的 Spring Data Neo4j 版本在将不同的会话工厂传播到存储库时存在错误。简而言之:现在无法完成这项工作(例如,您可以使用 Spring Data JPA)。
如果您需要(并且想要)存储库,我现在无法帮助您。然而,有效的是注入不同的会话工厂:
@Autowired
@Qualifier("myUserSessionFactory")
private SessionFactory myUserSessionFactory;
@Autowired
@Qualifier("rentalUserSessionFactory")
private SessionFactory rentalUserSessionFactory;
然后做类似
的事情
Map<String, Object> params = new HashMap<>();
params.put("name", "test");
ThingEntity t = this.myUserSessionFactory.openSession().queryForObject(
ThingEntity.class,
"MATCH (n:`Thing`) WHERE n.name = $name WITH n RETURN n", params);
不管我们的代码有没有bug,我推荐如下配置。对于主要 beans ("myUserconfiguration") 使用一个配置 class
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain1.ThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
@Configuration
@EnableNeo4jRepositories(
basePackages = Domain1Config.BASE_PACKAGE,
sessionFactoryRef = "myUserSessionFactory",
transactionManagerRef = "myUserTransactionManager"
)
@EntityScan(basePackageClasses = ThingEntity.class)
class Domain1Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain1";
@Primary
@Bean
@ConfigurationProperties("spring.data.neo4j")
public Neo4jProperties myNeo4jProperties() {
return new Neo4jProperties();
}
@Primary
@Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
return myNeo4jProperties().createConfiguration();
}
@Primary
@Bean
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), BASE_PACKAGE);
}
@Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
基本思想是使用 @ConfigurationProperties
将默认属性映射到 Neo4jProperties 的实例(我们的属性 class)并像我们创建操作配置一样使用它。
另一个会话工厂也一样:
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain2.OtherThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import static gh.neo4jogm.gh498.Domain2Config.BASE_PACKAGE;
@Configuration
@EnableNeo4jRepositories(
basePackages = BASE_PACKAGE,
sessionFactoryRef = "rentalUserSessionFactory",
transactionManagerRef = "rentalUsertransactionManager"
)
@EntityScan(basePackageClasses = OtherThingEntity.class)
class Domain2Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain2";
@Bean
@ConfigurationProperties("rental.data.neo4j")
public Neo4jProperties rentalNeo4jProperties() {
return new Neo4jProperties();
}
@Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
return rentalNeo4jProperties().createConfiguration();
}
@Bean
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), BASE_PACKAGE);
}
@Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
在这里,您将所有以 rental.data.neo4j
为前缀的属性映射到另一个属性实例。
预期行为
Trying to use two Neo4j instances with Spring boot and Spring data Neo4j
当前行为
Able to use only one Neo4j instances. Unable to use two repositories.
重现步骤(针对错误)
1. Run two Neo4j Instances
2. Create Data source configuration for both Neo4j Instances using spring boot.
3. Use Repository to access the Node entity
4. It will throw error
上下文
假设我是 运行 一家图书馆,正在向其他用户出租书籍。如果用户从我这里租书,相同的节点详细信息将出现在他们的存储库中,我将允许他们通过我的应用程序编辑节点实体(如添加关键字、添加关于书籍的亮点等)
因此在两个存储库中,节点详细信息将相同。
下面是应用程序。两个 Neo4j 存储库的属性详细信息。
我的 Neo4j 存储库详细信息
spring.data.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j
租用用户的 Neo4j 存储库详细信息 (通过 http 访问,在其他机器上是 运行)
rental.data.neo4j.uri=bolt://...:7687
rental.data.neo4j.username=neo4j
rental.data.neo4j.password=neo4j
以下是租赁用户的 Neo4j 配置:
@configuration
@EnableNeo4jRepositories(basePackages = "com.metadata.dao.rentallibrary", sessionFactoryRef = "rentalSessionFactory", transactionManagerRef = "rentalUsertransactionManager")
@EnableTransactionManagement
@EntityScan("com.metadata.dao")
public class rentalUserNeo4jConfiguration {
@Value("${rental.data.neo4j.uri}")
private String url;
@Value("${rental.data.neo4j.username}")
private String userName;
@Value("${rental.data.neo4j.password}")
private String password;
@Bean(name = "rentalSessionFactory")
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), "com.metadata.dao.rentallibrary.entity");
}
@Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)// "
.credentials(userName, password)
.build();
return configuration;
}
@Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
下面是我的图书馆的 Neo4j 配置细节:
@configuration
@EnableNeo4jRepositories(basePackages = "com.metadata.dao.mylibrary", sessionFactoryRef = "myUserSessionFactory", transactionManagerRef = "myUserTransactionManager")
@EnableTransactionManagement
public class MyUserNeo4jConfiguration {
@Value("${spring.data.neo4j.uri}")
private String url;
@Value("${spring.data.neo4j.username}")
private String userName;
@Value("${spring.data.neo4j.password}")
private String password;
@Bean(name = "myUserSessionFactory")
@Primary
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), "com.metadata.dao.mylibrary.entity");
}
@Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)
.credentials(userName, password)
.build();
return configuration;
}
@Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
我正在尝试使用会话工厂(通过限定符)访问两个存储库,它工作正常。但是我正在尝试通过我面临问题的存储库访问数据。
**Accessing through SessionFactory :**
@Autowired
@Qualifier(value = "myUserSessionFactory")
SessionFactory myUserSessionFactory;
@Autowired
@Qualifier(value = "rentalUserSessionFactory")
SessionFactory rentalUserSessionFactory;
以下是错误的详细信息,我在尝试通过以下方式访问数据时得到:
java.lang.IllegalArgumentException: Class class com.metadata.dao.Book is not a valid entity class. Please check the entity mapping.
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:88) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:40) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:469) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at org.springframework.data.neo4j.transaction.SharedSessionCreator$SharedSessionInvocationHandler.invoke(SharedSessionCreator.java:131) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at com.sun.proxy.$Proxy81.save(Unknown Source) ~[na:na]
org.neo4j.ogm.exception.core.TransactionManagerException: Transaction is not current for this thread
at org.neo4j.ogm.session.transaction.DefaultTransactionManager.rollback(DefaultTransactionManager.java:86) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.rollback(AbstractTransaction.java:65) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.neo4j.ogm.drivers.bolt.transaction.BoltTransaction.rollback(BoltTransaction.java:61) ~[neo4j-ogm-bolt-driver-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.close(AbstractTransaction.java:144) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.springframework.data.neo4j.transaction.Neo4jTransactionManager.doCleanupAfterCompletion(Neo4jTransactionManager.java:379) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
dao.mylibrary.entity 中的节点实体名称:书籍
dao.rentallibrary.entity 中的节点实体名称:RentedBook
请告诉我为什么在使用 Neo4j 存储库时会出现此问题?我们不能将两个 Neo4j 存储库与 Spring data neo4j & Spring boot 一起使用吗?还是我做错了什么?
我的环境
OGM Version used: 3.1.0
Java Version used: 1.8
Neo4J Version used:3.2.3
Bolt Driver Version used (if applicable): 3.1.0
Operating System and Version: Windows
Please let me know if you need any additional information.
更新 这已在 Spring Data Neo4j Lovelace RC1 中解决,我们写了一个小指南:https://michael-simons.github.io/neo4j-sdn-ogm-tips/using_multiple_session_factories
感谢您将此作为 GitHub 问题提交 #498。
似乎当前的 Spring Data Neo4j 版本在将不同的会话工厂传播到存储库时存在错误。简而言之:现在无法完成这项工作(例如,您可以使用 Spring Data JPA)。
如果您需要(并且想要)存储库,我现在无法帮助您。然而,有效的是注入不同的会话工厂:
@Autowired
@Qualifier("myUserSessionFactory")
private SessionFactory myUserSessionFactory;
@Autowired
@Qualifier("rentalUserSessionFactory")
private SessionFactory rentalUserSessionFactory;
然后做类似
的事情Map<String, Object> params = new HashMap<>();
params.put("name", "test");
ThingEntity t = this.myUserSessionFactory.openSession().queryForObject(
ThingEntity.class,
"MATCH (n:`Thing`) WHERE n.name = $name WITH n RETURN n", params);
不管我们的代码有没有bug,我推荐如下配置。对于主要 beans ("myUserconfiguration") 使用一个配置 class
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain1.ThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
@Configuration
@EnableNeo4jRepositories(
basePackages = Domain1Config.BASE_PACKAGE,
sessionFactoryRef = "myUserSessionFactory",
transactionManagerRef = "myUserTransactionManager"
)
@EntityScan(basePackageClasses = ThingEntity.class)
class Domain1Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain1";
@Primary
@Bean
@ConfigurationProperties("spring.data.neo4j")
public Neo4jProperties myNeo4jProperties() {
return new Neo4jProperties();
}
@Primary
@Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
return myNeo4jProperties().createConfiguration();
}
@Primary
@Bean
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), BASE_PACKAGE);
}
@Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
基本思想是使用 @ConfigurationProperties
将默认属性映射到 Neo4jProperties 的实例(我们的属性 class)并像我们创建操作配置一样使用它。
另一个会话工厂也一样:
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain2.OtherThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import static gh.neo4jogm.gh498.Domain2Config.BASE_PACKAGE;
@Configuration
@EnableNeo4jRepositories(
basePackages = BASE_PACKAGE,
sessionFactoryRef = "rentalUserSessionFactory",
transactionManagerRef = "rentalUsertransactionManager"
)
@EntityScan(basePackageClasses = OtherThingEntity.class)
class Domain2Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain2";
@Bean
@ConfigurationProperties("rental.data.neo4j")
public Neo4jProperties rentalNeo4jProperties() {
return new Neo4jProperties();
}
@Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
return rentalNeo4jProperties().createConfiguration();
}
@Bean
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), BASE_PACKAGE);
}
@Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
在这里,您将所有以 rental.data.neo4j
为前缀的属性映射到另一个属性实例。