grails、hibernate和多租户

pftdvrlh  于 2021-07-06  发布在  Java
关注(0)|答案(0)|浏览(252)

我们试图在grails2.5.3中实现基于模式的多租户,但是在hibernate(ver4.3.10)中遇到了一些问题。我们需要支持每请求租户切换,并且能够在应用程序运行时添加/删除租户(即数据源bean),而无需重新启动。
我们使用的abstractroutingdatasource与这里描述的类似:https://pritomkumar.blogspot.com/2014/10/grails-create-or-change-database.html
在resources.groovy中,以下代码创建switchabledatasource、root datasource,并为环境中定义的其他数据源创建bean:

parentDataSource(DriverManagerDataSource) { bean ->
            bean.'abstract' = true
            driverClassName = grailsApplication.config.dataSource.driverClassName
        }

        rootDataSource(DriverManagerDataSource) { bean ->
            bean.parent = parentDataSource
            bean.scope = 'prototype'
            url = grailsApplication.config.dataSource.url
            username = grailsApplication.config.dataSource.username
            password = grailsApplication.config.dataSource.password
        }

        Map dataSourceMapping = [:]
        dataSourceMapping[TenantManager.DATASOURCE_ADMIN] = ref('rootDataSource')

        //Find all existing tenant datasources
        Map tenantDataSources = grailsApplication.config.findAll {
            it.key.toString().startsWith(TenantManager.DATASOURCE_TENANT_PREFIX)
        }

        tenantDataSources.each { String key, ConfigObject dataSource ->
            "$key"(DriverManagerDataSource) { bean ->
                bean.parent = parentDataSource
                bean.scope = 'prototype'
                url = dataSource.url
                username = dataSource.username
                password = dataSource.password
            }

            dataSourceMapping[key] = ref("$key")
        }

        dataSource(SwitchableDataSource) {
            targetDataSources = dataSourceMapping
        }

我们有一个rest服务,它允许我们提供一个新的租户数据源,它使用类似的代码:

private Map registerDataSourceBean(Tenant tenant) {
        Map dataSourceParams
        ApplicationContext ctx = grailsApplication.mainContext
        String dataSourceName = TenantManager.getDataSourceNameForTenant(tenant.tenantId)

        if (!ctx.containsBean(dataSourceName)) {
            String dataSourceUser = DB_PREFIX + tenant.tenantId

            BeanBuilder bb = new BeanBuilder()
            bb.beans {
                "$dataSourceName"(DriverManagerDataSource) { bean ->
                    bean.parent = ref('parentDataSource')
                    bean.scope = 'prototype'
                    url = tenant.dataSourceUrl
                    username = dataSourceUser
                    password = dataSourceUser
                }
            }

            bb.registerBeans(ctx)
            dataSourceParams = [:]
            dataSourceParams['username'] = dataSourceUser
            dataSourceParams['url'] = tenant.dataSourceUrl
            dataSourceParams['dataSourceName'] = dataSourceName
            log.info("Created datasource [$dataSourceName]")
        } else {
            log.error("Datasource bean [$dataSourceName] already exists")
        }

        dataSourceParams
    }

作为这个过程的一部分,我们随后将数据源写入配置文件。在大多数情况下,这种模式是有效的,但我们看到了一些问题。
在运行时创建的数据源的连接方式似乎与在resources.groovy中创建的数据源不同。具体来说,运行时数据源在grailsapplication.maincontext.eventtriggeringinterceptor.datastores中没有hibernatedatastore,而在resources.groovy中没有。这限制了为租户创建持久性事件侦听器的能力,因为我们没有对该实体的引用(我不知道如何创建一个持久性事件侦听器)。这通常让我担心这个运行时DriverManager数据源没有正确使用hibernate。
也许我在这个过程中遗漏了一些步骤来正确地连接数据源以供使用。
如果有人知道我可能错过了什么,或者是谁在我之前走过这条路,我将非常感谢任何帮助。感谢您的光临!

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题