我真的很难使用 spring-data-neo4j
在Neo4j 4.0.0版本中,可以在数据库之间进行切换,而我需要这样做来实现一个多租户系统,每个租户都有自己的数据库。
然而,我需要实现多租户系统,每个租户都有自己的数据库。spring-data-neo4j
似乎没有提供任何方法在运行时用最新版本切换数据库(这也必须是线程安全的)。
我想的是在运行时创建一个单一的 sessionFactory
每位承租人
val sessionFactory = createTenantSessionFactory()
val session = sessionFactory.openSession()
val factory = Neo4jRepositoryFactory(session, mappingContext)
val repository = factory.getRepository(DesiredNeo4jRepository::class.java)
但是,我在使用这个方案时,遇到了并发性的问题,即使在一个线程中一个接一个地执行请求,但数据库中的结果却不对。
我想,这可能是因为我在这个方案中没有使用spring提供的事务管理支持,因为 Neo4jTransactionManager
是没有创造。
我意识到这是一个非常复杂的问题,但我是否针对这个问题采取了一个好的方法,还是有更好的替代方案我没有看到?
如果没有更好的方法,我怎么能用这个方案支持事务管理呢?
谢谢您的帮助!
我终于知道如何解决这个问题,目前使用了来自 https:/community.neo4j.comtspring-data-neo4j-4-0-release-multi-tenant12920。
所以我实现了一个 TenantContext
object ApplicationContext {
private val currentTenant = ThreadLocal<String>()
fun setCurrentTenant(tenantName: String) {
currentTenant.set(tenantName)
}
fun getCurrentTenant(): String? {
return currentTenant.get()
}
// Just a utility function
fun withTenantContext(tenant: String, handler: (() -> Unit)) {
val currentTenant = getCurrentTenant()
setCurrentTenant(tenant)
handler()
if (currentTenant != null) {
setCurrentTenant(currentTenant)
} else {
clearTenant()
}
}
fun clearTenant() {
currentTenant.remove()
}
}
并覆盖会话工厂。不幸的是, SessionFactory
没有暴露接口,所以我不得不重写它,并传递一个假的包和一个空的驱动程序(只要实现了 org.neo4j.ogm.driver.Driver
类,并将其留空)。)
这与其说是一个真正的解决方案,不如说是一个热补丁,同时也是在等待 spring-data-neo4j
但它在多线程上下文中工作,适合我的需求。
class MultiTenantSessionFactory(private val sessionFactories: ConcurrentMap<String, SessionFactory>) : SessionFactory(EmptyDriver(), "fake.package") {
override fun openSession(): Session {
return getSessionFactory(getCurrentTenantOrThrow()).openSession()
}
override fun close() {
getSessionFactory(getCurrentTenantOrThrow()).close()
}
private fun getSessionFactory(tenantName: String): SessionFactory {
return sessionFactories[tenantName] ?: throw UnregisteredSessionFactoryException(tenantName)
}
private fun getCurrentTenantOrThrow(): String {
return ApplicationContext.getCurrentTenant() ?: throw EmptyTenantContextException()
}
}
最后,只要为这个会话工厂创建一个Bean,同时使用 @EnableNeo4jRepositories
@Bean
fun sessionFactory(tenantRepository: TenantRepository): SessionFactory {
return MultiTenantSessionFactory(
tenantRepository.findAll()
.map { tenant -> tenant.name to initTenantSessionFactory(tenant) }
.toMap(ConcurrentHashMap())
)
}
你现在应该可以使用你所有的 Neo4jRepository
在多租户的情况下透明地。希望对大家有所帮助!