(Quick Reference)

3.3 数据源 - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

3.3 数据源

Since Grails is built on Java technology setting up a data source requires some knowledge of JDBC (the technology that doesn't stand for Java Database Connectivity).

If you use a database other than H2 you need a JDBC driver. For example for MySQL you would need Connector/J

Drivers typically come in the form of a JAR archive. It's best to use Ivy to resolve the jar if it's available in a Maven repository, for example you could add a dependency for the MySQL driver like this:

grails.project.dependency.resolution = {
    inherits("global")
    log "warn"
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()
        mavenCentral()
    }
    dependencies {
        runtime 'mysql:mysql-connector-java:5.1.16'
    }
}

Note that the built-in mavenCentral() repository is included here since that's a reliable location for this library.

If you can't use Ivy then just put the JAR in your project's lib directory.

Once you have the JAR resolved you need to get familiar Grails' DataSource descriptor file located at grails-app/conf/DataSource.groovy. This file contains the dataSource definition which includes the following settings:

  • driverClassName - The class name of the JDBC driver
  • username - The username used to establish a JDBC connection
  • password - The password used to establish a JDBC connection
  • url - The JDBC URL of the database
  • dbCreate - Whether to auto-generate the database from the domain model - one of 'create-drop', 'create', 'update' or 'validate'
  • pooled - Whether to use a pool of connections (defaults to true)
  • logSql - Enable SQL logging to stdout
  • formatSql - Format logged SQL
  • dialect - A String or Class that represents the Hibernate dialect used to communicate with the database. See the org.hibernate.dialect package for available dialects.
  • readOnly - If true makes the DataSource read-only, which results in the connection pool calling setReadOnly(true) on each Connection
  • properties - Extra properties to set on the DataSource bean. See the Commons DBCP BasicDataSource documentation.

A typical configuration for MySQL may be something like:

dataSource {
    pooled = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost/yourDB"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "yourUser"
    password = "yourPassword"
}

When configuring the DataSource do not include the type or the def keyword before any of the configuration settings as Groovy will treat these as local variable definitions and they will not be processed. For example the following is invalid:

dataSource {
    boolean pooled = true // type declaration results in ignored local variable
    …
}

Example of advanced configuration using extra properties:

dataSource {
    pooled = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost/yourDB"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "yourUser"
    password = "yourPassword"
    properties {
        maxActive = 50
        maxIdle = 25
        minIdle = 5
        initialSize = 5
        minEvictableIdleTimeMillis = 60000
        timeBetweenEvictionRunsMillis = 60000
        maxWait = 10000
        validationQuery = "/* ping */"
    }
}

既然Grails是基于Java技术来设置数据源的,那么一些JDBC的知识是必不可少的。

如果你的数据库并非H2,那么你至少还需要一个JDBC驱动。以MySQL为例,你需要下载Connector/J

驱动通常打包成JAR。如果你需要的jar在Maven的存储库中存在,那么最好是通过Ivy来解析它们,比如下面是对MySQL驱动的依赖:

grails.project.dependency.resolution = {
    inherits("global")
    log "warn"
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()
        mavenCentral()
    }
    dependencies {
        runtime 'mysql:mysql-connector-java:5.1.16'
    }
}

注意,此处引入了内置的mavenCentral()存储库,因为此jar包位于其中。

如果Ivy找不到,那么只需要将JAR放到你工程的lib目录即可。

一旦解决了JAR的问题,你需要来熟悉一下位于grails-app/conf/DataSource.groovy中的Grails数据源描述了。此文件包含如下所述的一些数据源的定义:

  • driverClassName - JDBC驱动的类名
  • username - 建立JDBC连接的用户名
  • password - 建立JDBC连接的密码
  • url - JDBC数据库的URL
  • dbCreate - 是否根据领域类自动生成数据库-可以是'create-drop'、'create'、'update'或者'validate'
  • pooled - 是否使用连接池(缺省是true)
  • logSql - 是否将SQL输出到字符终端
  • formatSql - 格式化SQL
  • dialect - Hibernate用于跟数据库通讯的方言(dialect),可以是字符串或者类名。可以通过org.hibernate.dialect来查看所支撑的方言。
  • readOnly - 如果是true那么此数据源就是只读的,这是通过调用连接池的ConnectionsetReadOnly(true)来实现的。
  • properties - 设置数据源的额外属性。更多请参考Commons DBCP的 BasicDataSource文档。

一个MySQL的典型配置可能如下:

dataSource {
    pooled = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost/yourDB"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "yourUser"
    password = "yourPassword"
}

在配置数据源的时候,不要在配置名前加入任何类型或者def关键字,因为Groovy将其视为一个本地变量定义而将其忽略。比如:

dataSource {
    boolean pooled = true // type declaration results in ignored local variable
    …
}

一个使用额外属性配置的高级示例如下:

dataSource {
    pooled = true
    dbCreate = "update"
    url = "jdbc:mysql://localhost/yourDB"
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    username = "yourUser"
    password = "yourPassword"
    properties {
        maxActive = 50
        maxIdle = 25
        minIdle = 5
        initialSize = 5
        minEvictableIdleTimeMillis = 60000
        timeBetweenEvictionRunsMillis = 60000
        maxWait = 10000
        validationQuery = "/* ping */"
    }
}

More on dbCreate

Hibernate can automatically create the database tables required for your domain model. You have some control over when and how it does this through the dbCreate property, which can take these values:

  • create - Drops the existing schemaCreates the schema on startup, dropping existing tables, indexes, etc. first.
  • create-drop - Same as create, but also drops the tables when the application shuts down cleanly.
  • update - Creates missing tables and indexes, and updates the current schema without dropping any tables or data. Note that this can't properly handle many schema changes like column renames (you're left with the old column containing the existing data).
  • validate - Makes no changes to your database. Compares the configuration with the existing database schema and reports warnings.
  • any other value - does nothing

You can also remove the dbCreate setting completely, which is recommended once your schema is relatively stable and definitely when your application and database are deployed in production. Database changes are then managed through proper migrations, either with SQL scripts or a migration tool like Liquibase (the Database Migration plugin uses Liquibase and is tightly integrated with Grails and GORM).

关于dbCreate

Hibernate能够根据你的领域类来自动创建数据库表。你可以通过dbCreate属性来进行一些控制,其可选值如下:

  • create - 在启动时候,先删除已存在的,包括表、索引等,然后创建。
  • create-drop - 同 create,不过在应用关闭的时候,也进行表删除。
  • update - 创建不存在的表和索引,并且在不删除表和数据的情况下更新表结构。注意此种情况于很多限制,比如你不能很好地处理重命名字段(旧有地字段依然保留)
  • validate - 不改变你数据库地任何信息,只是跟现有地数据库配置脚本进行比较,并且报告一个警告。
  • 其他 - 什么都不做

如果你的数据库变化相对稳定或者你的应用部署于生产环境,推荐你将dbCreate完全移除。数据库的变更迁移可以通过SQL脚本或者迁移工具,比如Liquibase数据库迁移 插件就是通过Liquibase来跟Grails和GORM紧密集成的)来完成。

3.3.1 数据源和环境

The previous example configuration assumes you want the same config for all environments: production, test, development etc.

Grails' DataSource definition is "environment aware", however, so you can do:

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    // other common settings here
}

environments { production { dataSource { url = "jdbc:mysql://liveip.com/liveDb" // other environment-specific settings here } } }

在前面的配置示例中,不管是在生产、测试还是开发环境中,我们假设所有的配置都是一样的,

但是Grails的数据源定义是可以跟环境相关的,因此,你可以象下面的示例那样进行处理:

dataSource {
    pooled = true
    driverClassName = "com.mysql.jdbc.Driver"
    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    // other common settings here
}

environments { production { dataSource { url = "jdbc:mysql://liveip.com/liveDb" // other environment-specific settings here } } }

3.3.2 JNDI数据源

Referring to a JNDI DataSource

Most Java EE containers supply DataSource instances via Java Naming and Directory Interface (JNDI). Grails supports the definition of JNDI data sources as follows:

dataSource {
    jndiName = "java:comp/env/myDataSource"
}

The format on the JNDI name may vary from container to container, but the way you define the DataSource in Grails remains the same.

引用JNDI数据源

大部分的Java EE容器支持 Java命名服务接口 (JNDI)的DataSource,Grails也支持如下格式的JNDI数据源定义:

dataSource {
    jndiName = "java:comp/env/myDataSource"
}

虽然不同的容器之间定义JNDI名字的格式有很大的差异,但是Grails中DataSource的定义却是保持一致的。

Configuring a Development time JNDI resource

The way in which you configure JNDI data sources at development time is plugin dependent. Using the Tomcat plugin you can define JNDI resources using the grails.naming.entries setting in grails-app/conf/Config.groovy:

grails.naming.entries = [
    "bean/MyBeanFactory": [
        auth: "Container",
        type: "com.mycompany.MyBean",
        factory: "org.apache.naming.factory.BeanFactory",
        bar: "23"
    ],
    "jdbc/EmployeeDB": [
        type: "javax.sql.DataSource", //required
        auth: "Container", // optional
        description: "Data source for Foo", //optional
        driverClassName: "org.h2.Driver",
        url: "jdbc:h2:mem:database",
        username: "dbusername",
        password: "dbpassword",
        maxActive: "8",
        maxIdle: "4"
    ],
    "mail/session": [
        type: "javax.mail.Session,
        auth: "Container",
        "mail.smtp.host": "localhost"
    ]
]

开发环境中配置JNDI资源

在开发环境中,配置JNDI数据源的方式是跟插件相关的。如果你是在用 Tomcat 插件的话,可以通过grails-app/conf/Config.groovy中的grails.naming.entries来配置JNDI资源,比如:

grails.naming.entries = [
    "bean/MyBeanFactory": [
        auth: "Container",
        type: "com.mycompany.MyBean",
        factory: "org.apache.naming.factory.BeanFactory",
        bar: "23"
    ],
    "jdbc/EmployeeDB": [
        type: "javax.sql.DataSource", //required
        auth: "Container", // optional
        description: "Data source for Foo", //optional
        driverClassName: "org.h2.Driver",
        url: "jdbc:h2:mem:database",
        username: "dbusername",
        password: "dbpassword",
        maxActive: "8",
        maxIdle: "4"
    ],
    "mail/session": [
        type: "javax.mail.Session,
        auth: "Container",
        "mail.smtp.host": "localhost"
    ]
]

3.3.3 自动数据库迁移

The dbCreate property of the DataSource definition is important as it dictates what Grails should do at runtime with regards to automatically generating the database tables from GORM classes. The options are described in the DataSource section:
  • create
  • create-drop
  • update
  • validate
  • no value

In development mode dbCreate is by default set to "create-drop", but at some point in development (and certainly once you go to production) you'll need to stop dropping and re-creating the database every time you start up your server.

It's tempting to switch to update so you retain existing data and only update the schema when your code changes, but Hibernate's update support is very conservative. It won't make any changes that could result in data loss, and doesn't detect renamed columns or tables, so you'll be left with the old one and will also have the new one.

Grails supports Rails-style migrations via the Database Migration plugin which can be installed by running


grails install-plugin database-migration

The plugin uses Liquibase and and provides access to all of its functionality, and also has support for GORM (for example generating a change set by comparing your domain classes to a database).

DataSource中的dbCreate属性是很重要的,正如其所暗示,Grails将根据此值和GORM类在运行时来自动生成数据库表。可选项已经在数据源章节中介绍:

  • create
  • create-drop
  • update
  • validate

开发模式下,dbCreate通常设置为"create-drop",但是当开发到一定程度(更进一步要运行于生产环境),你将不会再采用这种每次启动先删除再创建的方式。

当你想保留数据并且只想更新所变化的代码时,可以尝试使用update。不过Hibernate对更新的支撑是非常保守的。其在数据安全方面不能给你任何保证,此外它也不能自动检测到字段或者表的重命名,因此在新增的同时旧有的依然保留。

Grails现在支撑Rails风格的数据库迁移了,这是通过安装和运行 Database Migration 插件来实现的。


grails install-plugin database-migration

此插件以 Liquibase 为基础,除了具有原来的强大功能外,其还对GORM提供了支持(比如通过领域类和数据库的比较来自动生成变化内容)。

3.3.4 事务感知的数据源代理

The actual dataSource bean is wrapped in a transaction-aware proxy so you will be given the connection that's being used by the current transaction or Hibernate Session if one is active.

If this were not the case, then retrieving a connection from the dataSource would be a new connection, and you wouldn't be able to see changes that haven't been committed yet (assuming you have a sensible transaction isolation setting, e.g. READ_COMMITTED or better).

The "real" unproxied dataSource is still available to you if you need access to it; its bean name is dataSourceUnproxied.

You can access this bean like any other Spring bean, i.e. using dependency injection:

class MyService {

def dataSourceUnproxied … }

or by pulling it from the ApplicationContext:

def dataSourceUnproxied = ctx.dataSourceUnproxied

dataSource 实际上只是事务感知代理的封装,因此你得到的数据库连接是来自于当前事务或者当前活动的Hibernate的Session

除此之外,直接从dataSource获取的连接将是一个新连接,你将看不到任何没有提交的变化(假设你设置了事务隔离敏感度,比如READ_COMMITTED或者更高)。

那个"真实的"未被代理的dataSource对你来说,依然可用,只不过其bean名称是dataSourceUnproxied

你可用想其他Spring bean那样来访问此bean,比如使用依赖注入:

class MyService {

def dataSourceUnproxied … }

或者直接从ApplicationContext中获取:

def dataSourceUnproxied = ctx.dataSourceUnproxied

3.3.5 数据库管理界面

The H2 database console is a convenient feature of H2 that provides a web-based interface to any database that you have a JDBC driver for, and it's very useful to view the database you're developing against. It's especially useful when running against an in-memory database.

You can access the console by navigating to http://localhost:8080/appname/dbconsole in a browser. The URI can be configured using the grails.dbconsole.urlRoot attribute in Config.groovy and defaults to '/dbconsole'.

The console is enabled by default in development mode and can be disabled or enabled in other environments by using the grails.dbconsole.enabled attribute in Config.groovy. For example you could enable the console in production using

environments {
    production {
        grails.serverURL = "http://www.changeme.com"
        grails.dbconsole.enabled = true
        grails.dbconsole.urlRoot = '/admin/dbconsole'
    }
    development {
        grails.serverURL = "http://localhost:8080/${appName}"
    }
    test {
        grails.serverURL = "http://localhost:8080/${appName}"
    }
}

If you enable the console in production be sure to guard access to it using a trusted security framework.

H2数据库管理界面是在H2特性的基础上提供的一个基于WEB界面的数据库管理,用以管理任何基于JDBC的数据库,在开发阶段用来查看数据库非常有用,尤其在你的应用运行于数据库的内存模式时。

你可以在浏览器中通过 http://localhost:8080/appname/dbconsole 来使用访问。此URI可以通过配置Config.groovy中的grails.dbconsole.urlRoot属性来改变,缺省是'/dbconsole'

此界面在开发模式下缺省是有效的,你也可以通过修改Config.groovy中的grails.dbconsole.enabled属性来使其在其他环境模式下失效或者生效。比如,你可以在生产环境中使其生效:

environments {
    production {
        grails.serverURL = "http://www.changeme.com"
        grails.dbconsole.enabled = true
        grails.dbconsole.urlRoot = '/admin/dbconsole'
    }
    development {
        grails.serverURL = "http://localhost:8080/${appName}"
    }
    test {
        grails.serverURL = "http://localhost:8080/${appName}"
    }
}

如果你要在生产环境中使用此功能,请确保使用安全可信的框架来保护。

Configuration

By default the console is configured for an H2 database which will work with the default settings if you haven't configured an external database - you just need to change the JDBC URL to jdbc:h2:mem:devDB. If you've configured an external database (e.g. MySQL, Oracle, etc.) then you can use the Saved Settings dropdown to choose a settings template and fill in the url and username/password information from your DataSource.groovy.

配置

缺省情况下,如果你没有使用外部数据库,那么数据库管理界面是使用H2数据库的,其JDBC的URL配置成jdbc:h2:mem:devDB即可。但是如果你使用的是一个外部数据库(比如MySQL、 Oracle等),那你需要从下拉框中选择合适的JDBC配置模板,并且配置合适的url、用户名/密码,要确保跟DataSource.groovy的配置是一致的。

3.3.6 多数据源

By default all domain classes share a single DataSource and a single database, but you have the option to partition your domain classes into two or more DataSources.

缺省情况下,所有的领域类共享同一个DataSource和数据库,但是你还是有将领域类拆分到两个甚至更多个DataSource的选择的。

Configuring Additional DataSources

The default DataSource configuration in grails-app/conf/DataSource.groovy looks something like this:

dataSource {
    pooled = true
    driverClassName = "org.h2.Driver"
    username = "sa"
    password = ""
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}

environments { development { dataSource { dbCreate = "create-drop" url = "jdbc:h2:mem:devDb" } } test { dataSource { dbCreate = "update" url = "jdbc:h2:mem:testDb" } } production { dataSource { dbCreate = "update" url = "jdbc:h2:prodDb" } } }

This configures a single DataSource with the Spring bean named dataSource. To configure extra DataSources, add another dataSource block (at the top level, in an environment block, or both, just like the standard DataSource definition) with a custom name, separated by an underscore. For example, this configuration adds a second DataSource, using MySQL in the development environment and Oracle in production:

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'
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:h2:mem:testDb"
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            url = "jdbc:h2:prodDb"
        }
        dataSource_lookup {
            dialect = org.hibernate.dialect.Oracle10gDialect
            driverClassName = 'oracle.jdbc.driver.OracleDriver'
            username = 'lookup'
            password = 'secret'
            url = 'jdbc:oracle:thin:@localhost:1521:lookup'
            dbCreate = 'update'
        }
    }
}

You can use the same or different databases as long as they're supported by Hibernate.

配置额外的数据源

缺省的DataSource配置是位于grails-app/conf/DataSource.groovy中的,大体样子如下:

dataSource {
    pooled = true
    driverClassName = "org.h2.Driver"
    username = "sa"
    password = ""
}
hibernate {
    cache.use_second_level_cache = true
    cache.use_query_cache = true
    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}

environments { development { dataSource { dbCreate = "create-drop" url = "jdbc:h2:mem:devDb" } } test { dataSource { dbCreate = "update" url = "jdbc:h2:mem:testDb" } } production { dataSource { dbCreate = "update" url = "jdbc:h2:prodDb" } } }

上述示例配置了一个Spring bean名称为dataSourceDataSource。要配置额外的DataSource,需要增加另外一个自定义名称(以下划线分割)的dataSource(跟标准的DataSource类似,只不过要定义在在最外层、环境代码块或者同时两个地方)代码块即可。例如,以下代码的配置新增了第二个DataSource,其在开发环境下是MySQL数据库,在生产环境下是Oracle:

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'
        }
    }
    test {
        dataSource {
            dbCreate = "update"
            url = "jdbc:h2:mem:testDb"
        }
    }
    production {
        dataSource {
            dbCreate = "update"
            url = "jdbc:h2:prodDb"
        }
        dataSource_lookup {
            dialect = org.hibernate.dialect.Oracle10gDialect
            driverClassName = 'oracle.jdbc.driver.OracleDriver'
            username = 'lookup'
            password = 'secret'
            url = 'jdbc:oracle:thin:@localhost:1521:lookup'
            dbCreate = 'update'
        }
    }
}

你可以使用Hibernate所支持的相同和或者相异的数据库。

Configuring Domain Classes

If a domain class has no DataSource configuration, it defaults to the standard 'dataSource'. Set the datasource property in the mapping block to configure a non-default DataSource. For example, if you want to use the ZipCode domain to use the 'lookup' DataSource, configure it like this;

class ZipCode {

String code

static mapping = { datasource 'lookup' } }

A domain class can also use two or more DataSources. Use the datasources property with a list of names to configure more than one, for example:

class ZipCode {

String code

static mapping = { datasources(['lookup', 'auditing']) } }

If a domain class uses the default DataSource and one or more others, use the special name 'DEFAULT' to indicate the default DataSource:

class ZipCode {

String code

static mapping = { datasources(['lookup', 'DEFAULT']) } }

If a domain class uses all configured DataSources use the special value 'ALL':

class ZipCode {

String code

static mapping = { datasource 'ALL' } }

配置领域类

如果一个领域类没有配置DataSource,那么其缺省使用标准的'dataSource'。你可以在mapping代码块中设置datasource属性来配置一个非标准的DataSource。例如,你希望ZipCode使用名为'lookup'DataSource,其配置如下:

class ZipCode {

String code

static mapping = { datasource 'lookup' } }

一个领域类还可以有两个甚至更多个DataSources。这时候,只需要将datasources设置为一个名称的列表即可,比如:

class ZipCode {

String code

static mapping = { datasources(['lookup', 'auditing']) } }

如果一个领域类既使用缺省的又使用多于一个的DataSource,可以使用名称为'DEFAULT'来代表缺省的DataSource

class ZipCode {

String code

static mapping = { datasources(['lookup', 'DEFAULT']) } }

如果一个领域类要使用所有已经配置的DataSource,请使用特定名称'ALL'

class ZipCode {

String code

static mapping = { datasource 'ALL' } }

Namespaces and GORM Methods

If a domain class uses more than one DataSource then you can use the namespace implied by each DataSource name to make GORM calls for a particular DataSource. For example, consider this class which uses two DataSources:

class ZipCode {

String code

static mapping = { datasources(['lookup', 'auditing']) } }

The first DataSource specified is the default when not using an explicit namespace, so in this case we default to 'lookup'. But you can call GORM methods on the 'auditing' DataSource with the DataSource name, for example:

def zipCode = ZipCode.auditing.get(42)
…
zipCode.auditing.save()

As you can see, you add the DataSource to the method call in both the static case and the instance case.

命名空间和GORM方法

如果一个领域类使用了多于一个的DataSource,你可以将其每个DataSource名称作为命名空间,并且以此命名来执行GORM的方法调用。例如,下面示例的类有两个DataSource

class ZipCode {

String code

static mapping = { datasources(['lookup', 'auditing']) } }

当没有明确指定命名空间的时候,其指定的第一个DataSource被视为缺省,上例中其缺省命名空间是'lookup'。但是你也可以在'auditing'的DataSource上执行GORM方法,比如:

def zipCode = ZipCode.auditing.get(42)
…
zipCode.auditing.save()

如你所见,你可以在DataSource上进行静态和实例类型的方法调用。

Services

Like Domain classes, by default Services use the default DataSource and PlatformTransactionManager. To configure a Service to use a different DataSource, use the static datasource property, for example:

class DataService {

static datasource = 'lookup'

void someMethod(...) { … } }

A transactional service can only use a single DataSource, so be sure to only make changes for domain classes whose DataSource is the same as the Service.

Note that the datasource specified in a service has no bearing on which datasources are used for domain classes; that's determined by their declared datasources in the domain classes themselves. It's used to declare which transaction manager to use.

What you'll see is that if you have a Foo domain class in dataSource1 and a Bar domain class in dataSource2, and WahooService uses dataSource1, a service method that saves a new Foo and a new Bar will only be transactional for Foo since they share the datasource. The transaction won't affect the Bar instance. If you want both to be transactional you'd need to use two services and XA datasources for two-phase commit, e.g. with the Atomikos plugin.

服务类

跟领域类相似,服务类也是使用缺省的DataSourcePlatformTransactionManager。要配置服务使用另外一个不同的DataSource,请使用静态的(static)datasource属性,比如:

class DataService {

static datasource = 'lookup'

void someMethod(...) { … } }

一个支持事务的服务只能使用一个DataSource,因此请确保领域类的DataSource的名字要跟服务类中定义的一致。

注意,一个服务类的datasource不对领域类的datasources产生影响,后者由其自身的声明决定。服务类的datasource多用来声明要使用哪一个事务管理器。

假设你有两个数据源,领域类Foo属于dataSource1,Bar属于dataSource2,而WahooService使用dataSource1,此外还有一个方法来实现Foo和Bar的新增保存,那么只有Foo是支持事务的,因为他们共享dataSource1数据源。而Bar实例并不受事务影响。如果你想两者都支持事务,那么你需要两个服务类和支持两阶段提交的XA数据源,比如使用Atomikos插件。

XA and Two-phase Commit

Grails has no native support for XA DataSources or two-phase commit, but the Atomikos plugin makes it easy. See the plugin documentation for the simple changes needed in your DataSource definitions to reconfigure them as XA DataSources.

XA和两阶段(Two-phase)提交

Grails并没有直接支持XA DataSources 或者 两阶段提交,但是Atomikos 插件使两者变得容易。此插件的文档有介绍如何比较容易的将现有的DataSource定义重新配置为XA DataSources。