【问题标题】:Using two databases for an application in grails在 grails 中为一个应用程序使用两个数据库
【发布时间】:2010-11-11 09:15:53
【问题描述】:

我正在 grails 中创建一个应从一个数据库读取并写入另一个数据库的应用程序。我为此要求创建了 datasources.groovy 并安装了数据源插件。但是,我在执行 sql 查询时遇到了如何使用这个数据源的问题(select * from........etc. etc)。

例如。以下是我在操作中运行查询的方式。我使用的是自定义查询而不是 gorm。

已编辑:

class TuneController {   

    def dataSource_ds2

    def list = {

        String nameSql = "select name from emp where id=3345"
        Sql sql = new Sql(dataSource_ds2)
        String name = sql.rows(nameSql)
        println(name)
    }
}

在上述情况下,datasources 未被读取并且具有空值。 是否有适用于此要求的示例代码。

我错过了什么吗?

编辑:

我的 Datasources.groovy 条目如下。

datasources = { 

    datasource(name:'ds2') {
        domainClasses([com.Tune])
        readOnly(true)
        driverClassName('oracle.jdbc.driver.OracleDriver')
        url('jdbc:oracle:thin:@test-ofr.wellmanage.com:1521:OFRS1')         
        username('test')
        password('test')
        environments(['development'])
        dbCreate('do-not-bother')
        logSql(true)
        dialect(org.hibernate.dialect.Oracle10gDialect)
        hibernate {
            cache {
                use_second_level_cache(false)
                use_query_cache(false)
            }
        }
    }
}

【问题讨论】:

    标签: database grails


    【解决方案1】:

    辅助数据源可通过依赖注入获得,但它们的名称基于 Datasources.groovy 中的名称。例如,如果您定义了一个名为“foo”的数据源,那么您将使用def dataSource_foo 注入它:

    class MyController {
    
       def dataSource_foo
    
       def list = {
          String nameSql = "select name from emp where id=3345"
          Sql sql = new Sql(dataSource_foo)
          def rows = sql.rows(nameSql)
          ...
       }
    }
    

    请注意,您必须将def dataSource_foo 作为类范围字段,而不是放在您的操作(或方法)中。对于每个依赖注入都是如此 - 如果它在方法或闭包中,它只是一个方法范围的变量。

    【讨论】:

    • 明白你的意思。根据您的建议编辑了我的代码。请检查我编辑的代码。我的数据源名称是 ds2。所以现在我将我的数据源定义为 def dataSource_ds2。还尝试了其他选项 def ds2。仍然收到相同的错误“必须指定非空连接”。我错过了什么吗?
    • 你认为我写数据源的方式有问题
    • @Burt:谢谢你的帮助。通过了。这个答案和你很棒的插件肯定值得一票。
    【解决方案2】:

    只是为了更新这个问题的答案(我刚刚得到一个需要使用两个不同 mysql 数据库的新项目)。我不得不升级到 grails 2.0(是的,我一直懒得从 1.3.7 升级),因为它内置了对多个数据源的支持(无需使用插件)。

    Grails 2.0 - multiple datasources

    从示例中,您只需在 DataSource.groovy 文件中设置 DB

    environments {
    development {
        dataSource {
            dbCreate = "create-drop"
            url = "jdbc:h2:mem:devDb"
        }
        dataSource_lookup {
            dialect = org.hibernate.dialect.MySQLInnoDBDialect
            driverClassName = 'com.mysql.jdbc.Driver'
            username = 'lookup'
            password = 'secret'
            url = 'jdbc:mysql://localhost/lookup'
            dbCreate = 'update'
        }
    }
    

    然后在域类中,指定哪个数据源:

    class ZipCode {
    
        String code
    
        static mapping = { datasource 'lookup' } 
     }
    

    【讨论】:

    • 完全相同的代码对我不起作用。 (唯一的区别是我使用的是 postgres)。我运行 dbm-gorm-diff 来创建迁移,但迁移中没有用于构建表的代码。您能否确认此代码对您有效,并且您能够生成和运行迁移???
    • 它不适用于带有条件查询的 grails 2.4.4,适用于动态查找器。对于条件查询,我必须像 Domain.lookup.createCriteria 那样做——即使域被配置为使用查找数据源。
    【解决方案3】:

    我想知道为什么没有人在这里提到'c3p0:c3p0:0.9.1.2'插件。

    这是在 grails 应用程序中实现多个数据库的最佳实践

    Buildconfig.groovy

    compile 'c3p0:c3p0:0.9.1.2'
    

    数据源

     dataSource {
                dialect = 'com.example.hibernateutil.MySQL5InnoDBDialectBitFixed'
                dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', ''
                driverClassName = "com.mysql.jdbc.Driver"
                url = "jdbc:mysql://127.0.0.1/demo
                username = "root"
                password = ""
            }
    
            dataSource_Demo {
                dialect = 'com.example.hibernateutil.MySQL5InnoDBDialectBitFixed'
                dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', ''
                driverClassName = "com.mysql.jdbc.Driver"
                url = "jdbc:mysql://127.0.0.1/demo2"
                username = "root"
                password = ""
            }
    

    resources.groovy

    beans = {
    
    
       dataSource_Demo(ComboPooledDataSource) { bean ->
            bean.destroyMethod = 'close'
            //use grails' datasource configuration for connection user, password, driver and JDBC url
            user = grailsApplication.config.dataSource_Demo.username
            password = grailsApplication.config.dataSource_Demo.password
            driverClass = grailsApplication.config.dataSource_Demo.driverClassName
            jdbcUrl = grailsApplication.config.dataSource_Demo.url
            idleConnectionTestPeriod = 2 * 60 * 60 //2 hours
            testConnectionOnCheckin = true
        }
    
        /**
         * c3P0 pooled data source that allows 'DB keepalive' queries
         * to prevent stale/closed DB connections
         * Still using the JDBC configuration settings from DataSource.groovy
         * to have easy environment specific setup available
         */
        dataSource(ComboPooledDataSource) { bean ->
            bean.destroyMethod = 'close'
            //use grails' datasource configuration for connection user, password, driver and JDBC url
            user = grailsApplication.config.dataSource.username
            password = grailsApplication.config.dataSource.password
            driverClass = grailsApplication.config.dataSource.driverClassName
            jdbcUrl = grailsApplication.config.dataSource.url
            idleConnectionTestPeriod = 2 * 60 * 60 //2 hours
            testConnectionOnCheckin = true
        }
    }
    

    【讨论】:

      【解决方案4】:

      我在我参与的最后一个项目的 BootStrap 中执行了此操作。请记住,有效的 Java 代码也是有效的 Groovy(大多数情况下),您不必按照“Grails 方式”做所有事情。只需以您喜欢的方式连接到“来自”数据库,并通过 Grails 域对象操作将内容存储在 Grails 数据源中。示例代码:

      try {
          Connection con = DriverManager.getConnection ("jdbc:xxxx", "username", "password")
          ResultSet resultSet = con.createStatement().executeQuery("SELECT * FROM the_table")
          while(resultSet.next()) {
              DomainObject domainObjectInstance = new DomainObject(attributeA: resultSet.getString('attributeA'), attributeB: resultSet.getString('attributeB'))
              if (!domainObjectInstance.save(flush: true)) {
                  println "Unable to save DomainObject: ${domainObjectInstance.errors}"
              }
          }
      } catch (SQLException e) {
          e.printStackTrace();
      }
      

      【讨论】:

      • 谢谢埃里克。我明白你的意思。但要求严格说“在 GRAILS 中执行”:(
      【解决方案5】:

      我将我的数据源更新为以下内容,它工作正常。我不确定它背后的原因是什么。

       datasources = {  
      
          datasource(name:'ds2') { 
              domainClasses([com.Tune]) 
              readOnly(true) 
              driverClassName('oracle.jdbc.driver.OracleDriver') 
              url('jdbc:oracle:thin:@test-ofr.tnic.com:1521:OFRS1')          
              username('test') 
              password('test') 
              environments(['development']) 
              dbCreate('do-not-bother') 
              logSql(true) 
              dialect(org.hibernate.dialect.Oracle10gDialect) 
              hibernate { 
                  cache { 
                     provider_class('net.sf.ehcache.hibernate.EhCacheProvider')
                     use_second_level_cache(true)
                     use_query_cache(true)
                  } 
              } 
          } 
      } 
      

      【讨论】:

        【解决方案6】:

        如何在 Grails 服务中通过 SQL 使用多个数据源的示例。

        提示:您可以使用TestServiceWithInjectionTestService。两者都可以正常工作。

        DataSource.groovy

        dataSource {
            pooled = true
            jmxExport = true
            driverClassName = "com.mysql.jdbc.Driver"
            dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
        }
        hibernate {
            cache.use_second_level_cache = true
            cache.use_query_cache = false
        //    cache.region.factory_class = 'org.hibernate.cache.SingletonEhCacheRegionFactory' // Hibernate 3
            cache.region.factory_class = 'org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory' // Hibernate 4
            singleSession = true // configure OSIV singleSession mode
            flush.mode = 'manual' // OSIV session flush mode outside of transactional context
        }
        
        // environment specific settings
        environments {
            development {
                dataSource {
                    dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', ''
                    url = "jdbc:mysql://localhost:3306/database1"
                    username = "root"
                    password = "password"
                }
                dataSource_second {
                    driverClassName = "com.mysql.jdbc.Driver"
                    dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
                    dbCreate = "update" // one of 'create', 'create-drop', 'update', 'validate', ''
                    url = "jdbc:mysql://localhost:3306/database2"
                    username = "root"
                    password = "password"
                }
            }
            test {
                dataSource {
                    //Used by local test run (grails test-app)
                    dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
                    url = "jdbc:mysql://test-server.com:3306/test_ci"
                    username = "root"
                    password = "password"
                }
            }
        }
        

        TestServiceWithInjection.groovy

        package com.github.biniama
        
        import grails.transaction.Transactional
        import groovy.sql.Sql
        
        import javax.annotation.PostConstruct
        
        @Transactional
        class TestService {
        
            def dataSource_second
        
            Sql sql
        
            @PostConstruct
            def initSql() {
                sql = new Sql(dataSource_second)
            }
        
            def getData() {
                def q = "SELECT id FROM job LIMIT 1"
                return sql.rows(q)
            }
        }
        

        TestService.groovy

        package com.github.biniama
        
        import grails.transaction.Transactional
        import groovy.sql.Sql
        
        @Transactional
        class TestService {
        
        private Sql sql
        
        void setDataSource_second(def dataSource) {
            sql = new Sql(dataSource)
        }
        
        Integer getData() {
            def q = "SELECT id FROM job LIMIT 1"
            return sql.rows(q)
        }
        

        }

        TestController.groovy

        package com.github.biniama
        
        class TestController {
        
          TestService testService
        
          def index() {
            Integer result = testService.getData()
            render "Returned value is ${result}"
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2012-04-08
          • 2018-08-10
          • 2020-05-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多