grails / grails-database-migration

Grails® framework Database Migration Plugin
Apache License 2.0
98 stars 115 forks source link

NoSuchBeanDefinitionException for transactionManager bean occurs when using additional dataSource in 3.1.0.RC1 #167

Open nobeans opened 4 years ago

nobeans commented 4 years ago

Task List

Steps to Reproduce

  1. Define an additional dataSources in application.yml as follows:

    dataSources:
        liquibase:
            url: jdbc:h2:mem:liquibaseDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
            pooled: true
            jmxExport: true
            driverClassName: org.h2.Driver
            username: sa
            password: ''
  2. Use the dataSource for grails.plugin.databasemigration.

    grails:
        plugin:
            databasemigration:
                liquibase:
                    updateOnStartFileName: changelog.groovy
                    updateOnStart: true
  3. Run grails application.

Expected Behaviour

The application run up normally.

Actual Behaviour

The error occurs:

2020-03-02 13:11:03.195 ERROR --- [  restartedMain] liquibase.changelog.ChangeSet            : Change Set changelog.groovy::test-0001:: failed.  Error: No bean named 'transactionManager_dataSource_liquibase' available
2020-03-02 13:11:03.345 ERROR --- [  restartedMain] o.s.b.d.LoggingFailureAnalysisReporter   :

***************************
APPLICATION FAILED TO START
***************************

Description:

A component required a bean named 'transactionManager_dataSource_liquibase' that could not be found.

Action:

Consider defining a bean named 'transactionManager_dataSource_liquibase' in your configuration.

Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
        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:498)
        at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.reflect.UndeclaredThrowableException
        at org.springframework.util.ReflectionUtils.rethrowRuntimeException(ReflectionUtils.java:152)
        at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:807)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:97)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:458)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:445)
        at grails4.issue.Application.main(Application.groovy:11)
        ... 5 more
Caused by: liquibase.exception.MigrationFailedException: Migration failed for change set changelog.groovy::test-0001:::
     Reason: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager_dataSource_liquibase' available
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:637)
        at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:53)
        at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:83)
        at liquibase.Liquibase.update(Liquibase.java:202)
        at liquibase.Liquibase.update(Liquibase.java:179)
        at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:353)
        at org.grails.plugins.databasemigration.liquibase.GrailsLiquibase.performUpdate(GrailsLiquibase.groovy:83)
        at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:305)
        at org.springframework.beans.factory.InitializingBean$afterPropertiesSet.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:119)
        at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin$_doWithApplicationContext_closure2$_closure5.doCall(DatabaseMigrationGrailsPlugin.groovy:86)
        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:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
        at groovy.lang.Closure.call(Closure.java:405)
        at groovy.lang.Closure.call(Closure.java:421)
        at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140)
        at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
        at grails.gorm.transactions.GrailsTransactionTemplate$execute.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:123)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction$0.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:176)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:47)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
        at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin$_doWithApplicationContext_closure2.doCall(DatabaseMigrationGrailsPlugin.groovy:75)
        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:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
        at groovy.lang.Closure.call(Closure.java:405)
        at groovy.lang.Closure.call(Closure.java:421)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2296)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2281)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2334)
        at org.codehaus.groovy.runtime.dgm$188.invoke(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:244)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
        at org.grails.plugins.databasemigration.DatabaseMigrationGrailsPlugin.doWithApplicationContext(DatabaseMigrationGrailsPlugin.groovy:59)
        at org.grails.plugins.DefaultGrailsPlugin.doWithApplicationContext(DefaultGrailsPlugin.java:507)
        at org.grails.plugins.AbstractGrailsPluginManager.doPostProcessing(AbstractGrailsPluginManager.java:223)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:259)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:402)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:359)
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:896)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
        ... 9 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionManager_dataSource_liquibase' available
        at io.micronaut.spring.context.factory.MicronautBeanFactory.doGetBean(MicronautBeanFactory.java:730)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:273)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:204)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1111)
        at org.springframework.beans.factory.BeanFactory$getBean$1.call(Unknown Source)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.getTransactionManager(DatabaseMigrationTransactionManager.groovy:33)
        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:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
        at org.codehaus.groovy.runtime.metaclass.MethodMetaProperty$GetBeanMethodMetaProperty.getProperty(MethodMetaProperty.java:76)
        at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.callGroovyObjectGetProperty(GetEffectivePogoPropertySite.java:68)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:117)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction$0.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:176)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withTransaction(DatabaseMigrationTransactionManager.groovy:107)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager$withTransaction$1.callCurrent(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:156)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:176)
        at org.grails.plugins.databasemigration.DatabaseMigrationTransactionManager.withNewTransaction(DatabaseMigrationTransactionManager.groovy:60)
        at org.grails.plugins.databasemigration.liquibase.GroovyChange.withNewTransaction(GroovyChange.groovy:312)
        at org.grails.plugins.databasemigration.liquibase.GroovyChange.generateStatements(GroovyChange.groovy:150)
        at liquibase.change.AbstractChange.generateStatementsVolatile(AbstractChange.java:287)
        at liquibase.changelog.ChangeSet.execute(ChangeSet.java:595)
        ... 85 more

Environment Information

Example Application

nobeans commented 4 years ago

The implementation of GroovyChange seems wrong.

GORM set up beans for each dataSource as follows.

The current implementation of GroovyChange uses dataSource bean name as dataSource name. For the default dataSource, the both of them are same, dataSource. But for the additional dataSource which dataSource name is liquibase, the dataSource bean name become dataSource_liquibase internally. This difference makes using wrong transactionManager bean, transactionManager_dataSource_liquibase.

https://github.com/grails-plugins/grails-database-migration/blob/master/src/main/groovy/org/grails/plugins/databasemigration/liquibase/GroovyChange.groovy#L312 https://github.com/grails-plugins/grails-database-migration/blob/master/src/main/groovy/org/grails/plugins/databasemigration/DatabaseMigrationTransactionManager.groovy#L28-L32

To fix it, you get rid of the prefix of dataSource_ of the bean name if its exists.

nobeans commented 4 years ago

157 seems same issue though it's about sessionFactory.

demus-nine commented 4 years ago

A workaround is to alias the incorrect names to the correct names in spring/resources.groovy.