Grails 具有3个或更多数据源的GORM集成测试

Grails 具有3个或更多数据源的GORM集成测试,grails,groovy,gorm,spock,grails-3.3,Grails,Groovy,Gorm,Spock,Grails 3.3,我的集成测试失败,出现错误,“org.hibernate.hibernateeexception:当您尝试与2个以上的数据源交互时,找不到当前线程的会话”。运行应用程序时不会出现此问题,请参阅 正确的设置方法是什么 我希望避免我发现的需要使用with newtransaction闭包来包装GORM查询的解决方法。这会破坏代码的可读性 环境: host:TestingMultDbs user$ ./grailsw -version | Grails Version: 3.3.6 | Groov

我的集成测试失败,出现错误,“org.hibernate.hibernateeexception:当您尝试与2个以上的数据源交互时,找不到当前线程的会话”。运行应用程序时不会出现此问题,请参阅

正确的设置方法是什么

我希望避免我发现的需要使用with newtransaction闭包来包装GORM查询的解决方法。这会破坏代码的可读性

环境

host:TestingMultDbs user$ ./grailsw -version
| Grails Version: 3.3.6
| Groovy Version: 2.4.7
| JVM Version: 1.8.0_181
    development:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
test:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
// Can only declare 1 @Transactional
//    @Transactional("db2") -- causes db3 to fail
//    @Transactional("db3") -- causes db2 to fail
//    @Transactional(["db2","db3"]) -- doesn't exist
@Transactional
void "Test interaction with all 3 databases"() {
    given:
    new DefaultDb(f1: "test").save()
    new Db2Example(f1: "test").save()
    new Db3Example(f1: "test").save()

    when:
    def value1 = DefaultDb.findByF1("test")
    def value2 = Db2Example.findByF1("test")
    def value3 = Db3Example.findByF1("test")

    then:
    value1
    value2
    value3
}
void "Test default db"() {
    given:
    new DefaultDb(f1: "test").save()

    when:
    def value = DefaultDb.findByF1("test")

    then:
    value
}

@Transactional("db2")
void "Test default db2"() {
    given:
    new Db2Example(f1: "test").save()

    when:
    def value = Db2Example.findByF1("test")

    then:
    value
}

@Transactional("db3")
void "Test default db3"() {
    given:
    new Db3Example(f1: "test").save()

    when:
    def value = Db3Example.findByF1("test")

    then:
    value
}
数据库配置

host:TestingMultDbs user$ ./grailsw -version
| Grails Version: 3.3.6
| Groovy Version: 2.4.7
| JVM Version: 1.8.0_181
    development:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
test:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
// Can only declare 1 @Transactional
//    @Transactional("db2") -- causes db3 to fail
//    @Transactional("db3") -- causes db2 to fail
//    @Transactional(["db2","db3"]) -- doesn't exist
@Transactional
void "Test interaction with all 3 databases"() {
    given:
    new DefaultDb(f1: "test").save()
    new Db2Example(f1: "test").save()
    new Db3Example(f1: "test").save()

    when:
    def value1 = DefaultDb.findByF1("test")
    def value2 = Db2Example.findByF1("test")
    def value3 = Db3Example.findByF1("test")

    then:
    value1
    value2
    value3
}
void "Test default db"() {
    given:
    new DefaultDb(f1: "test").save()

    when:
    def value = DefaultDb.findByF1("test")

    then:
    value
}

@Transactional("db2")
void "Test default db2"() {
    given:
    new Db2Example(f1: "test").save()

    when:
    def value = Db2Example.findByF1("test")

    then:
    value
}

@Transactional("db3")
void "Test default db3"() {
    given:
    new Db3Example(f1: "test").save()

    when:
    def value = Db3Example.findByF1("test")

    then:
    value
}
测试失败

host:TestingMultDbs user$ ./grailsw -version
| Grails Version: 3.3.6
| Groovy Version: 2.4.7
| JVM Version: 1.8.0_181
    development:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
test:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
// Can only declare 1 @Transactional
//    @Transactional("db2") -- causes db3 to fail
//    @Transactional("db3") -- causes db2 to fail
//    @Transactional(["db2","db3"]) -- doesn't exist
@Transactional
void "Test interaction with all 3 databases"() {
    given:
    new DefaultDb(f1: "test").save()
    new Db2Example(f1: "test").save()
    new Db3Example(f1: "test").save()

    when:
    def value1 = DefaultDb.findByF1("test")
    def value2 = Db2Example.findByF1("test")
    def value3 = Db3Example.findByF1("test")

    then:
    value1
    value2
    value3
}
void "Test default db"() {
    given:
    new DefaultDb(f1: "test").save()

    when:
    def value = DefaultDb.findByF1("test")

    then:
    value
}

@Transactional("db2")
void "Test default db2"() {
    given:
    new Db2Example(f1: "test").save()

    when:
    def value = Db2Example.findByF1("test")

    then:
    value
}

@Transactional("db3")
void "Test default db3"() {
    given:
    new Db3Example(f1: "test").save()

    when:
    def value = Db3Example.findByF1("test")

    then:
    value
}
通过测试

host:TestingMultDbs user$ ./grailsw -version
| Grails Version: 3.3.6
| Groovy Version: 2.4.7
| JVM Version: 1.8.0_181
    development:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
test:
    dataSource:
        dbCreate: create-drop
        url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        logSql: true
    dataSources:
        db2:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
        db3:
          dbCreate: create-drop
          url: jdbc:h2:mem:devDb3;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
// Can only declare 1 @Transactional
//    @Transactional("db2") -- causes db3 to fail
//    @Transactional("db3") -- causes db2 to fail
//    @Transactional(["db2","db3"]) -- doesn't exist
@Transactional
void "Test interaction with all 3 databases"() {
    given:
    new DefaultDb(f1: "test").save()
    new Db2Example(f1: "test").save()
    new Db3Example(f1: "test").save()

    when:
    def value1 = DefaultDb.findByF1("test")
    def value2 = Db2Example.findByF1("test")
    def value3 = Db3Example.findByF1("test")

    then:
    value1
    value2
    value3
}
void "Test default db"() {
    given:
    new DefaultDb(f1: "test").save()

    when:
    def value = DefaultDb.findByF1("test")

    then:
    value
}

@Transactional("db2")
void "Test default db2"() {
    given:
    new Db2Example(f1: "test").save()

    when:
    def value = Db2Example.findByF1("test")

    then:
    value
}

@Transactional("db3")
void "Test default db3"() {
    given:
    new Db3Example(f1: "test").save()

    when:
    def value = Db3Example.findByF1("test")

    then:
    value
}

zyro23在这里解释了解决方案:

检查更改注册表。ChainedTransactionManagerPostProcessor(从3.3.0起默认禁用):并尝试通过application.yml重新启用

grails:
  transaction:
    chainedTransactionManagerPostProcessor:
      enabled: true
对于该配置,省略connection属性应该是可行的(或者说没有什么区别)


但是,请确保您理解链式事务处理的含义,即尽力而为的两阶段提交(“be2pc”)方法。

注意:这在Grails 3.2中适用,这是在升级到3.3后发现的。然而,Github中提供的示例是一个干净的3.3.6项目。升级指南包括一个附加参数:blacklistPattern,这原本是为了防止修复。