【问题标题】:Error upgrading Grails app from 3.1.10 to 3.2.5将 Grails 应用程序从 3.1.10 升级到 3.2.5 时出错
【发布时间】:2017-06-27 11:24:50
【问题描述】:

我正在尝试将我的 Grails 应用程序从 3.1.10 升级到 3.2.5,以使用新的 GORM 等,但在达到数据库迁移时启动失败。

我明白了:

    INFO 2/9/17 2:08 PM: liquibase: Can not use class org.grails.plugins.databasemigration.liquibase.GormDatabase as a Liquibase service because it does not have a no-argument constructor
ERROR org.springframework.boot.SpringApplication - Application startup failed
org.springframework.transaction.HeuristicCompletionException: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction
at org.grails.transaction.ChainedTransactionManager.commit(ChainedTransactionManager.java:183)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:150)
at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
at grails.transaction.GrailsTransactionTemplate$execute.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:31)
at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin$_doWithApplicationContext_closure2.doCall(DatabaseMigrationGrailsPlugin.groovy:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1426)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2068)
at org.codehaus.groovy.runtime.dgm$164.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin.doWithApplicationContext(DatabaseMigrationGrailsPlugin.groovy:63)
at org.grails.plugins.DefaultGrailsPlugin.doWithApplicationContext(DefaultGrailsPlugin.java:523)
at org.grails.plugins.AbstractGrailsPluginManager.doPostProcessing(AbstractGrailsPluginManager.java:224)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:246)
at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:337)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:882)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:372)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.boot.GrailsApp.run(GrailsApp.groovy:388)
at grails.boot.GrailsApp.run(GrailsApp.groovy:375)
at grails.boot.GrailsApp$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at saasapi.Application.main(Application.groovy:8)
Caused by: org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:704)
at org.grails.transaction.MultiTransactionStatus.commit(MultiTransactionStatus.java:73)
at org.grails.transaction.ChainedTransactionManager.commit(ChainedTransactionManager.java:156)
... 56 common frames omitted

我已将以下依赖项更新或添加到我的 build.gradle:

buildscript {
    ...
    dependencies {
        ....
        classpath "org.grails.plugins:hibernate5:6.0.4"
        classpath 'org.grails.plugins:database-migration:3.0.0'
    }
}

dependencies {
    ...
    runtime 'mysql:mysql-connector-java:5.1.40'
    compile "org.grails.plugins:hibernate5"
    compile "org.hibernate:hibernate-core:5.1.1.Final"
    compile "org.hibernate:hibernate-ehcache:5.1.1.Final"
    runtime 'org.grails.plugins:database-migration:3.0.0'
    compile 'org.liquibase:liquibase-core:3.5.3'
    compile 'org.grails.plugins:mongodb'
}

人们之前在这些 Github 问题中看到过 liquibase 错误“PM: liquibase: Can not use class org.grails.plugins.databasemigration.liquibase.GormDatabase as a Liquibase service because it does not have a no-argument constructor”:

https://github.com/grails-plugins/grails-database-migration/issues/81

https://github.com/grails-plugins/grails-database-migration/issues/64#issuecomment-256739113

但对他们来说,这并不是一个重大错误。

当我尝试更新到 Grails 3.2.3 时,我还看到了 liquibase 错误消息,但除此之外一切正常(迁移日志也不可见)。可能问题就出在这里,Grails 3.2.3 使用的是 Spring Boot 1.4.1,而 Grails 3.2.5 使用的是 Spring Boot 1.4.4。

无论如何我迷路了,我希望有人可以帮助我。

编辑:我使用数据库迁移插件来设置我的数据库表,我现在也使用它来更改它。我还在启动时启用了数据库迁移。

EDIT2:问题本身似乎与数据库迁移没有太大关系

我使用多个数据源(application.yml 中的相关部分):

hibernate:
    cache:
        queries: false
        use_second_level_cache: true
        use_query_cache: false
        region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory

dataSources:
    dataSource:
        pooled: true
        jmxExport: true
        driverClassName: com.mysql.jdbc.Driver
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        dbCreate: none
        properties:
            testOnBorrow: true
            validationQuery: SELECT 1
    myOtherDataSource:
        pooled: true
        jmxExport: true
        driverClassName: net.sourceforge.jtds.jdbc.Driver
        dialect: org.hibernate.dialect.SQLServerDialect
        dbCreate: none

environments:
    development:
        dataSources:
            dataSource:
                url: jdbc:mysql://localhost/my_default_db?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true
                username: my_user
                password: my_pass
            myOtherDataSource:
                driverClassName: com.mysql.jdbc.Driver
                dialect: org.hibernate.dialect.MySQL5InnoDBDialect
                url: jdbc:mysql://localhost/my_other_db?useUnicode=yes&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
                username: my_user
                password: my_pass

当启动时没有数据库迁移时,我也可以启动我的应用程序,但随后出现与 db 相关的不同错误:

ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - PooledConnection has already been closed.
ERROR org.grails.web.errors.GrailsExceptionResolver - SQLException occurred when processing request: [GET] /my-endpoint
......
Caused by: org.hibernate.exception.GenericJDBCException: could not prepare statement
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:182)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:148)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1934)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1903)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1881)
at org.hibernate.loader.Loader.doQuery(Loader.java:925)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doList(Loader.java:2622)
at org.hibernate.loader.Loader.doList(Loader.java:2605)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2434)
at org.hibernate.loader.Loader.list(Loader.java:2429)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.listForCriteria(AbstractHibernateQuery.java:700)
at org.grails.orm.hibernate.query.AbstractHibernateQuery.list(AbstractHibernateQuery.java:690)
at org.grails.datastore.gorm.finders.FindAllByFinder.invokeQuery(FindAllByFinder.java:54)
at org.grails.datastore.gorm.finders.FindAllByFinder$1.doInSession(FindAllByFinder.java:48)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:318)
at org.grails.datastore.gorm.finders.AbstractFinder.execute(AbstractFinder.java:42)
at org.grails.datastore.gorm.finders.FindAllByFinder.doInvokeInternal(FindAllByFinder.java:45)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:174)
at org.grails.datastore.gorm.finders.DynamicFinder.invoke(DynamicFinder.java:374)
at org.grails.datastore.gorm.GormStaticApi$_methodMissing_closure2.doCall(GormStaticApi.groovy:169)
.....
Caused by: java.sql.SQLException: PooledConnection has already been closed.
at org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy$LazyConnectionInvocationHandler.invoke(LazyConnectionDataSourceProxy.java:376)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(TransactionAwareDataSourceProxy.java:240)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:146)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:172)
... 66 common frames omitted

【问题讨论】:

    标签: grails spring-boot database-migration


    【解决方案1】:

    我的设置几乎和你一样,我没有任何问题。我最重要的变化是我使用了 hibernate-core 和 ehcache 的 5.1.3 Final 和 org.grails.plugins:hibernate5:6.0。 6.我没有 mongodb 依赖项。

    • 您有多个数据源吗?
    • 它是否在不运行任何迁移文件的情况下启动?

    【讨论】:

    • 是的,我有多个不同的数据源。但只有一个用于数据库迁移。我将在我的原始帖子中提供我的 application.yml 中的相关部分。是的,它确实在不运行迁移文件的情况下启动。但是后来我得到了与数据库连接相关的各种不同的错误。我将在我的原始帖子中提供来自错误堆栈跟踪的有意义的示例行。
    【解决方案2】:

    我在使用 Grails-3.2.5/3.2.6 时遇到了几乎相同的问题。 请尝试 Grails-3.2.4 看看问题是否仍然存在。

    【讨论】:

      【解决方案3】:

      使用多个数据源我有同样的问题。它只发生在默认数据源上,它看起来像 GrailsTemplate 它试图恢复以前的状态但未能这样做,因为事务已提交。

        org.springframework.transaction.HeuristicCompletionException: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction
          at org.grails.transaction.ChainedTransactionManager.commit(ChainedTransactionManager.java:183)
          at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:150)
          at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
          at grails.transaction.GrailsTransactionTemplate$execute.call(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
          at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:31)
          at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction.call(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
          at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin$_doWithApplicationContext_closure2.doCall(DatabaseMigrationGrailsPlugin.groovy:77)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:497)
          at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1426)
          at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
          at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
          at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
          at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
          at groovy.lang.Closure.call(Closure.java:414)
          at groovy.lang.Closure.call(Closure.java:430)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
          at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2068)
          at org.codehaus.groovy.runtime.dgm$164.invoke(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
          at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
          at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
          at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin.doWithApplicationContext(DatabaseMigrationGrailsPlugin.groovy:63)
          at org.grails.plugins.DefaultGrailsPlugin.doWithApplicationContext(DefaultGrailsPlugin.java:523)
          at org.grails.plugins.AbstractGrailsPluginManager.doPostProcessing(AbstractGrailsPluginManager.java:224)
          at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:246)
          at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
          at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
          at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
          at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383)
          at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:337)
          at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:882)
          at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
          at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545)
          at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
          at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762)
          at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:372)
          at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
          at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
          at grails.boot.GrailsApp.run(GrailsApp.groovy:388)
          at grails.boot.GrailsApp.run(GrailsApp.groovy:375)
          at grails.boot.GrailsApp$run.call(Unknown Source)
          at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
          at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
          at scd.Application.main(Application.groovy:8)
        Caused by: org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction
          at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:704)
          at org.grails.transaction.MultiTransactionStatus.commit(MultiTransactionStatus.java:73)
          at org.grails.transaction.ChainedTransactionManager.commit(ChainedTransactionManager.java:156)
          ... 56 common frames omitted
      

      【讨论】:

      • 我做了一个没有失败的小测试用例。在我从原始项目复制域类后,它再次失败。经过反复试验,我发现如果您有 32 个或更多域类,则会发生此错误。
      【解决方案4】:

      我为此创建了一个问题,示例应用程序重现了这种行为:https://github.com/grails/grails-core/issues/10477

      [更新]:

      我终于明白了。 Grails 将为 dataSources 下的每个配置创建一个平台事务管理器,并为默认数据源创建一个。在您的示例中,这看起来像 [dataSource,myOtherDataSource,dataSource]。这显然不是应该发生的事情。在 GORM 文档中指定您应该使用:

      dataSource: 
        ..
      dataSources: 
         myOtherDataSource: 
      

      这会奏效。 Grails 创建了两个平台事务管理器,这是正确的行为。

      但 Databasemigration 期望所有数据源都在 dataSources 配置块中,因此它找不到默认数据源。 我已经为此创建了一个补丁,并会在修复另一个相关错误后立即为此创建一个 pullrequest;

      Grails 不会在多数据源配置的 applicationContext 中发布名为“dataSource”的默认数据源。 我已将此添加到问题https://github.com/grails/grails-core/issues/10477

      [更新 2]:

      我创建了两个拉取请求来解决这个问题:

      grails-plugins/grails-database-migration/pull/123

      grails/grails-core/pull/10478

      这些解决了我系统上的问题。我无法发布两个链接,因为根据 stackoverflow 我没有足够的声誉:S

      【讨论】:

      • 我知道 Stack Overflow 建议不要在 cmets 中感谢,但仍然感谢您创建该问题。
      猜你喜欢
      • 2014-05-07
      • 2015-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-06
      • 1970-01-01
      • 2018-06-07
      相关资源
      最近更新 更多