【问题标题】:Unable to dynamically provision a GORM-capable data source in Grails 3无法在 Grails 3 中动态配置支持 GORM 的数据源
【发布时间】:2017-05-25 08:49:07
【问题描述】:

我们正在实施一个多租户应用程序(每个租户的数据库),并希望包括对新租户的动态配置而无需重新启动服务器。这是 Grails 3.2.9 / GORM 6。

其中包括在运行时创建一个数据源,而不是在应用程序启动时在application.yml 中进行配置。

根据the documentation (11.2.5. Adding Tenants at Runtime),存在用于在运行时添加租户的 ConnectionSources API,但是以这种方式创建的 ConnectionSource 似乎没有在 Spring 中正确注册(用于数据源、会话和事务管理器的 bean)并且 Grails 抱怨缺少bean 当我们尝试使用新的数据源时。

我们期望当我们使用 ConnectionSources API 为一个新的数据库创建连接源时,Grails 应该按照我们应用程序中的 GORM Domains 用所有的表来初始化它,执行 Bootstrap.groovy 等,就像它一样对于application.yml 中静态配置的源,这也不会发生。

所以我的问题是 ConnectionSources API 的目的是否与我们尝试使用它的目的不同,或者它还没有完成/测试。

【问题讨论】:

  • 我有一个与您类似的问题,所以我很想看看您是否得到任何答复。我正在尝试为每个租户做一个模式。到目前为止,我可以成功地运行与数据库迁移运行的代码基本相同的代码,这使我能够为特定于模式的表和特定于默认模式的表保留单独的变更集。但是,当我尝试在特定模式中简单地创建域类时,会出现语法错误。没有太多关于这种数据库管理方法的信息,所以我很好奇你们提供了哪些解决方案。
  • 目前没有收到任何回复。现在我们解决了如果不重新启动就无法配置租户的问题。

标签: spring grails grails-orm


【解决方案1】:

我是想回到你身边。我确实设法找到了解决方案。现在这是针对每个客户的架构,而不是每个客户的数据库,但我怀疑它很容易适应。我首先使用直接的 Groovy Sql 对象创建模式,如下所示:

void createAccountSchema(String tenantId) {
    Sql sql = null
    try {
        sql = new Sql(dataSource as DataSource)
        sql.withTransaction {
            sql.execute("create schema ${tenantId}" as String)
        }
    } catch (Exception e) {
        log.error("Unable to create schema for tenant $tenantId", e)
        throw e
    } finally {
        sql?.close()
    }
}

然后我运行与 Liquibase 插件相同的代码,但有一些简单的默认值,如下所示:

void updateAccountSchema(String tenantId) {
    def applicationContext = Holders.applicationContext

    // Now try create the tables for the schema
    try {
        GrailsLiquibase gl = new GrailsLiquibase(applicationContext)
        gl.dataSource = applicationContext.getBean("dataSource", DataSource)
        gl.dropFirst = false
        gl.changeLog = 'changelog-m.groovy'
        gl.contexts = []
        gl.labels = []
        gl.defaultSchema = tenantId
        gl.databaseChangeLogTableName = defaultChangelogTableName
        gl.databaseChangeLogLockTableName = defaultChangelogLockTableName
        gl.afterPropertiesSet() // this runs the update command
    } catch (Exception e) {
        log.error("Exception trying to create new account schema tables for $tenantId", e)
        throw e
    }
}

最后,我告诉 Hibernate 新架构如下:

        try {
            hibernateDatastore.addTenantForSchema(tenantId)
        } catch (Exception e) {
            log.error("Exception adding tenant schema for ${tenantId}", e)
            throw e
        }

在任何你看到我提到“hibernateDatastore”或“dataSource”的地方,我都有 Grails 注入的内容,如下所示:

def hibernateDatastore
def dataSource

protected String defaultChangelogTableName = "databasechangelog"
protected String defaultChangelogLockTableName = "databasechangeloglock"

希望这会有所帮助。

【讨论】:

  • 非常感谢,我会试试这个并最终将您的帖子标记为答案。
猜你喜欢
  • 1970-01-01
  • 2017-12-02
  • 2016-01-12
  • 2016-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多