Grails 2 服务中的多个动态数据源

Posted

技术标签:

【中文标题】Grails 2 服务中的多个动态数据源【英文标题】:Grails 2 multiple dynamic datasources in services 【发布时间】:2012-06-07 03:08:09 【问题描述】:

我正在开发一个必须访问多个数据源的 Grails 应用程序。数据源在默认数据库中定义(即它们存储在那里,我必须调用默认数据库以检索我必须准备连接到的数据源名称列表)。当服务器启动时,我检索数据库列表,创建数据源 bean 并注入它们。所有动态添加的数据库在结构上都是相同的(即具有相同的表和域对象结构)。

This question 是我得到的最接近有用代码的部分,但这并不是我所需要的。

问题 #1

当我注册数据源 bean 时,它们会显示在我期望的位置,但 Grails 不会拾取它们。

这就是我添加它们的方式:

// Register datasource bean
def beanName = 'dataSource_devDB1'

BeanBuilder bb = new BeanBuilder()
bb.beans 
    "$beanName"(BasicDataSource)  
        url = "jdbc:h2:devDB1Db;MVCC=TRUE"
        pooled = true
        driverClassName = "org.h2.Driver"
        username = "sa"
        password = ""            
    


bb.registerBeans(grailsApplication.mainContext)

// check that it registered
def ctx = grailsApplication.mainContext
def ctxlist = ctx2.beanDefinitionNames.findAllit.contains( 'dataSource' )

log.info "ctxlist = " + ctxlist

打印出来:

[dataSource, dataSourceUnproxied, dataSource_devDB1]

当我这样做时,我可以对默认数据源执行操作,就是这样。

问题 #2

如果我将所有数据源声明为Datasource.groovy 文件的一部分,那么我可以对所有数据库执行操作,但不能对as advertised by the documentation

如果我对我的域对象进行静态映射,它会起作用:

static mapping = datasources(['devDB1', 'devDB2', 'DEFAULT')] or datasource = 'ALL'

但我想要将所有这些作为服务的一部分执行,并声明我的域对象使用所有数据源。

在服务中声明数据源不起作用:

class secureDBService

  static datasource = "devDB1"

  def readWriteMethod()
   .....
  // this always uses the default datasource ignoring the static property above.
  // the only time it uses devDB1 is if I declare it as part of the domain datasource
  // mapping
  

无论如何,这将始终使用默认数据源。它使用正确数据源的唯一时间是如果在域对象上我列出了有问题的数据源。


那么,有没有人:

    尝试添加动态数据源成功了?

    使用 grails 服务在数据源之间切换?

    (这将是一个非常棒的额外内容,作为“顶部的樱桃”)成功使用多个数据源和 Spring 安全核心?如何切换安全插件的数据源?

谢谢

--

【问题讨论】:

在这一点上,我几乎可以接受任何人告诉我他们已经使用 Grails 服务以多租户(多数据源)模式成功运行 Grails 来决定数据库。任何人?如果是,怎么做? springandgrailsmusings.blogspot.ca/2011/02/… 我还需要与此非常相似的场景的帮助。 @Kyle 你能解决这个在 grails 服务中切换数据源的问题吗? 您好,正在尝试清理未答复的内容。你解决了吗?也许你可以回答你自己的问题。 【参考方案1】:

我从事过类似的项目,其中应用程序必须从默认数据库中检索数据源列表(连接字符串),并连接到每个数据源并使用石英作业执行操作。

我实现它的方式是,连接到应用程序中的每个数据源(不是来自 DataSorce.groovy)并编写 SQL 而不是 HQL。

import groovy.sql.Sql

class SqlService
    Sql getDbConnection(String connectionString, String dbUser, String dbPassword)
        def sql = Sql.newInstance(connectionString, dbUser, dbPassword, "driver_class")
        return sql
    

从上面的代码中获取sql连接,使用sql.execute "SQL STATEMENT"执行SQL查询,关闭sql连接。 Here 是 Sql 类文档。

【讨论】:

【参考方案2】:

我有两个不同的数据源用于 Grails 2.3.11。我将 1 个数据源用于我的 H2 数据库,另一个用于 Oracle 数据库。我不得不将 Hibernate 4 与 Grails 2.3 一起使用。在我的BuildConfig.groovy 中,我指定了对休眠 4 的依赖:

runtime ":hibernate4:4.3.5.4"

在我的 DataSource.groovy 文件中,我使用了以下 Hibernate 缓存设置:

hibernate 
    cache.use_second_level_cache = true
    cache.use_query_cache = false
    cache.region.factory_class = 'org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory'
    singleSession = true // configure OSIV singleSession mode

(旁注:如果没有缓存设置,我会收到以下 CacheManager 错误,“另一个未命名的 CacheManager 已存在于同一 VM 中”。https://jira.grails.org/browse/GPCACHEEHCACHE-13 有一个关于此问题的公开错误报告,但一旦我将设置放入错误消失的地方。)

然后我定义了我的数据源:

environments 
    development 
        dataSource_oracle 
            pooled = true
            dialect = org.hibernate.dialect.Oracle10gDialect
            driverClassName = 'oracle.jdbc.OracleDriver'
            username = 'user'
            password = 'pass'
            url = 'jdbc:oracle:thin:@(serverName):(port):(SID)'
            dbCreate = 'validate'
        
        dataSource 
            dbCreate = "update"
            url = "jdbc:h2:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE"
            properties 
               jmxEnabled = true
               initialSize = 5
               maxActive = 50
               minIdle = 5
               maxIdle = 25
               maxWait = 10000
               maxAge = 10 * 60000
               timeBetweenEvictionRunsMillis = 5000
               minEvictableIdleTimeMillis = 60000
               validationQuery = "SELECT 1"
               validationQueryTimeout = 3
               validationInterval = 15000
               testOnBorrow = true
               testWhileIdle = true
               testOnReturn = false
               jdbcInterceptors = "ConnectionState"
               defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED
            
        
    

默认情况下,我的域类使用 H2 数据库,我将我的 Oracle 数据源指定为:

class MyService 

    def dataSource_oracle
    static transactional = true

    def getMethod() 
        assert dataSource_oracle != null, "dataSource is null! Please check your configuration!"
        def sql = Sql.newInstance(dataSource_oracle)
        ...
    

在上面,我允许依赖注入为服务提供 oracle 数据源def dataSource_oracle。如果我想使用 H2 数据源,我将数据源声明为 def dataSource 并允许 DI 注入我的其他数据源。


我无法让这两个数据源按照http://grails.github.io/grails-doc/2.3.11/guide/conf.html#multipleDatasources 的文档中指定的方式工作。通过将数据源声明为 dataSource 和 dataSource_lookup 然后将其用作:

class DataService 
   static datasource = 'lookup'

   void someMethod(...) 
      …
   
 

但是我能够使用上述解决方案


【讨论】:

【参考方案3】:

您可以在单个应用程序中添加多个数据源,并在服务中访问它们。

首先需要在resources.groovy中添加基础数据源。

首先导入 BasicDataSource

import org.apache.commons.dbcp.BasicDataSource;

然后

    switch (grails.util.GrailsUtil.environment) 
    case "development":
        firstDataSource( BasicDataSource ) 
            driverClassName = "net.sourceforge.jtds.jdbc.Driver"
            url = "jdbc:jtds:sqlserver://localhost:1433;DatabaseName=<Db_name>"
            username = "sa"
            password = "root"
            String SqlServerInstance = "SQLEXPRESS";
            url = url + ";" + SqlServerInstance;
        
        break

    case "test":
        firstDataSource( BasicDataSource ) 

            driverClassName = "net.sourceforge.jtds.jdbc.Driver"
            url = "jdbc:jtds:sqlserver://localhost:1433;DatabaseName=<Db_name>"
            username = "sa"
            password = "root"
            String SqlServerInstance = "SQLEXPRESS";
            url = url + ";" + SqlServerInstance;            
        break;


与您可以添加更多数据源的方式相同,上述代码将为您提供除默认数据源之外的更多数据源可供访问。 我使用switch为不同的环境配置相同的数据源,同样的方法可以添加更多。

并且在服务中可以通过以下方式访问它:

BasicDataSource firstDataSource;
Connection con = firstDataSource.getConnection();

然后就可以使用连接对象了。

我觉得应该有帮助

【讨论】:

这无助于回答原始问题。他需要从另一个数据库连接而不是平面文件动态创建 dataSource bean。我有同样的问题。 Grails 似乎没有一种很好的“友好”方式来使用主要上下文 dataSource bean 重新引导域类。我希望有人能回答我们的问题。 嗯可能是..我认为这可能会有所帮助..因为将其全部发布在 cmets 中是不合适的..【参考方案4】:

为 grails 使用分片插件来解决您的问题

【讨论】:

以上是关于Grails 2 服务中的多个动态数据源的主要内容,如果未能解决你的问题,请参考以下文章

Grails 2.4.2 - 动态引用默认数据源

如何在 Grails 中动态选择服务

在 Grails 2.2 中是不是可以对 mongodb 动态属性进行单元测试?

Grails 和子域

Symfony2 中的多个动态防火墙和 CAS 服务器

您可以通过 Grails 中的脚手架使用动态查找器或分组表吗?