Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
12-17-2019 02:48 AM
Hi all, I'm new to neo4j and just integrating neo4j with spring data to our web application where the back-end is written in java. We already use spring, hibernate and ms-sql. Also use the multi-tenant as tenant per database. So every tenant has it own database.
We now integrate neo4j with spring-data and want also have a neo4j instance(connection) per tenant.
For now I did some nasty hacky workaround by creating a own classes "class MultiTenantNeo4jSessionFactory extends SessionFactory" that holds the connection per tenant and gives back the right SessionFactory for a "class MultiTenantNeo4jTransactionManager extends AbstractPlatformTransactionManager", which is the same as the Neo4jTransacionManger but uses the MultiTenantNeo4jSessionFactory to get the right Neo4jSessionFactory.
This is hacky because I also needed to copy some private classes that not supposed to be copied at all. Like "class SessionTenantHolder extends SessionHolder" that is used by Neo4jTransactionObject and also used in SessionFactoryUtils where it is cast.
Above not the case anymore, after some investigation I only needed a own "class MultiTenantNeo4jSessionFactory extends SessionFactory". That can be given to the Neo4jTransactionManager Like below:
package my.company.neo4j.configuration;
import java.util.HashMap;
import java.util.Map;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import my.company.tenant.TenantContextHolder;
import my.company.tenant.TenantInitializer;
public class MultiTenantNeo4jSessionFactory extends SessionFactory implements TenantInitializer {
private Map<String, SessionFactory> m_tenantSessionFactories = new HashMap<>();
private String[] m_packages;
public MultiTenantNeo4jSessionFactory(Configuration configuration, String masterPackage, String... packages) {
super(configuration, masterPackege);
m_packages = packages;
}
@Override
public Session openSession() {
String tenantLabel = TenantContextHolder.getContext().getTenantLabel();
return m_tenantSessionFactories.get(tenantLabel).openSession();
}
@Override
public void close() {
String tenantLabel = TenantContextHolder.getContext().getTenantLabel();
m_tenantSessionFactories.get(tenantLabel).close();
}
@Override
public void initialize() {
String tenantLabel = TenantContextHolder.getContext().getTenantLabel();
if (tenantLabel.equals("tenant1")) {
m_tenantSessionFactories.put(tenantLabel, new SessionFactory(new org.neo4j.ogm.config.Configuration.Builder().uri("bolt://localhost:7681").credentials("neo4j", "test").build(), m_packages));
} else if (tenantLabel.equals("tenant2")) {
m_tenantSessionFactories.put(tenantLabel, new SessionFactory(new org.neo4j.ogm.config.Configuration.Builder().uri("bolt://localhost:7682").credentials("neo4j", "test").build(), m_packages));
}
}
SessionFactory getSessionFactory() {
String tenantLabel = TenantContextHolder.getContext().getTenantLabel();
return m_tenantSessionFactories.get(tenantLabel);
}
@Override
public void destroy() {
m_tenantSessionFactories.values().forEach(session -> session.close());
}
}
//...//
package my.company.neo4j.configuration;
import org.neo4j.ogm.session.SessionFactory;
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;
@Configuration
@EnableNeo4jRepositories(basePackages = "my.company.neo4j", sessionFactoryRef = "neo4jSessionFactory", transactionManagerRef = "neo4JtransactionManager")
public class Neo4jEducatorConfiguration {
@Bean
public SessionFactory neo4jSessionFactory() {
org.neo4j.ogm.config.Configuration masterConfiguration = new org.neo4j.ogm.config.Configuration.Builder().uri("bolt://localhost:7687").credentials("neo4j", "test").build();
return new MultiTenantNeo4jSessionFactory(masterConfiguration, "my.company.neo4j.master", "my.company.neo4j");
}
@Bean
public Neo4jTransactionManager neo4JtransactionManager() {
return new Neo4jTransactionManager(neo4jSessionFactory());
}
}
TenantContextHolder and TenantInitializer are own code, but you guys get the point.
So it works, but we are not sure if this is the way to go. So that leaves me with questions like:
12-18-2019 02:53 AM
Here's a link to some of the most recent discussions on multi-tenancy Multi-Tenancy on Neo4j. There's a lot of good info here about ways to implement multi-tenancy and Neo4j's road map.
12-20-2019 01:32 AM
Tnx, already scanned that post but did not get a full understanding what was possible at neo4j 3.x and 4.0, but found the document Neo4j_EE_4.0_MR2_Doc.pdf in that post helpful to see a glimpse of the future.
Nevertheless I found my solution in creating a MultiTenantNeo4jSessionFactory to serve SessionFactory per Tenant. I will take a look at this again when upgrading to 4.0 and consider then if this approach is still valid.
All the sessions of the conference are now available online