与Flyway / Spring和H2嵌入式数据库相关的模式问题

时间:2013-02-20 04:41:09

标签: spring h2 flyway

我正在构建一个使用MySQL数据库的Spring 3 MVC应用程序,并且最近将Flyway集成到解决方案中以管理数据库迁移。我已根据Flyway documentation成功配置了我的applicationContext.xml,以便在应用程序启动时,Flyway将迁移到最新版本。

我无法让Flyway与我的单元/功能测试很好地配合使用。我正在使用Spring Data JPA作为我的数据访问层,并构建了一些JUnit测试来测试一些自定义查询。

我用于这些测试的应用程序配置是:

<jdbc:embedded-database id="dataSource" type="H2" />

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
  <property name="driverClassName" value="org.h2.Driver"/>
  <property name="url" value="jdbc:h2:mem:medical_claims_tracker;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;MODE=MySQL;INIT=CREATE SCHEMA IF NOT EXISTS medical_claims_tracker" />
</bean>

<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource"/>
    <property name="schemas" value="medical_claims_tracker"/>
    <property name="sqlMigrationPrefix" value="Migration_"/>
</bean>

当我运行单元测试时(通过Eclipse或使用Maven),我得到以下异常:

ERROR: org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@4cd4544] to prepare test instance [name.hines.steven.medical_claims_tracker.repositories.ExpenseRepositoryTest@1664a9b]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:103)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:73)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway' defined in class path resource [tests_persistence-applicationContext.xml]: Invocation of init method failed; nested exception is com.googlecode.flyway.core.api.FlywayException: Error setting current schema to medical_claims_tracker
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:532)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:741)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:106)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:57)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
    ... 24 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway' defined in class path resource [tests_persistence-applicationContext.xml]: Invocation of init method failed; nested exception is com.googlecode.flyway.core.api.FlywayException: Error setting current schema to medical_claims_tracker
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:285)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:439)
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:277)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:71)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1506)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1474)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    ... 37 more
Caused by: com.googlecode.flyway.core.api.FlywayException: Error setting current schema to medical_claims_tracker
    at com.googlecode.flyway.core.Flyway.execute(Flyway.java:1250)
    at com.googlecode.flyway.core.Flyway.migrate(Flyway.java:820)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483)
    ... 54 more
Caused by: org.h2.jdbc.JdbcSQLException: Schema "medical_claims_tracker" not found; SQL statement:
SET SCHEMA "medical_claims_tracker" [90079-160]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:169)
    at org.h2.message.DbException.get(DbException.java:146)
    at org.h2.engine.Database.getSchema(Database.java:1501)
    at org.h2.command.dml.Set.update(Set.java:290)
    at org.h2.command.CommandContainer.update(CommandContainer.java:73)
    at org.h2.command.Command.executeUpdate(Command.java:219)
    at org.h2.jdbc.JdbcPreparedStatement.execute(JdbcPreparedStatement.java:181)
    at com.googlecode.flyway.core.dbsupport.JdbcTemplate.execute(JdbcTemplate.java:280)
    at com.googlecode.flyway.core.dbsupport.h2.H2DbSupport.setCurrentSchema(H2DbSupport.java:79)
    at com.googlecode.flyway.core.Flyway.execute(Flyway.java:1247)
    ... 62 more

我无法弄清楚如何让H2数据库识别出我想要使用名为medical_claims_tracker的模式这一事实。我使用this answer来帮助我尝试不同的连接网址和this answer,以帮助我确定在测试期间使用的applicationContext覆盖。

我怀疑这与H2在初始创建之后但在运行测试之前删除模式有关,但我认为DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;会为我解决这个问题。有趣的是,如果我删除了flyway bean config中的模式规范:

<bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource"/>
    <property name="sqlMigrationPrefix" value="Migration_"/>
</bean>

我得到了一个不同的例外:

INFO : com.googlecode.flyway.core.metadatatable.MetaDataTableImpl - Creating Metadata table: "public"."schema_version"
ERROR: org.springframework.test.context.TestContextManager - Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@4bd27069] to prepare test instance [name.hines.steven.medical_claims_tracker.repositories.ExpenseRepositoryTest@64d22462]
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:103)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:73)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway' defined in class path resource [tests_persistence-applicationContext.xml]: Invocation of init method failed; nested exception is com.googlecode.flyway.core.api.FlywayException: Error executing statement at line 17: CREATE TABLE "public"."schema_version" (
    "version_rank" INT NOT NULL,
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50) NOT NULL,
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INT,
    "installed_by" VARCHAR(30) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "execution_time" INT NOT NULL,
    "success" BOOLEAN NOT NULL
)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:532)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:741)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:106)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:57)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
    at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
    ... 24 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway' defined in class path resource [tests_persistence-applicationContext.xml]: Invocation of init method failed; nested exception is com.googlecode.flyway.core.api.FlywayException: Error executing statement at line 17: CREATE TABLE "public"."schema_version" (
    "version_rank" INT NOT NULL,
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50) NOT NULL,
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INT,
    "installed_by" VARCHAR(30) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "execution_time" INT NOT NULL,
    "success" BOOLEAN NOT NULL
)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1486)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:285)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:439)
    at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:277)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:139)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:79)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:71)
    at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:85)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1506)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1474)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    ... 37 more
Caused by: com.googlecode.flyway.core.api.FlywayException: Error executing statement at line 17: CREATE TABLE "public"."schema_version" (
    "version_rank" INT NOT NULL,
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50) NOT NULL,
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INT,
    "installed_by" VARCHAR(30) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "execution_time" INT NOT NULL,
    "success" BOOLEAN NOT NULL
)
    at com.googlecode.flyway.core.dbsupport.SqlStatement.execute(SqlStatement.java:78)
    at com.googlecode.flyway.core.dbsupport.SqlScript.execute(SqlScript.java:94)
    at com.googlecode.flyway.core.metadatatable.MetaDataTableImpl$1.doInTransaction(MetaDataTableImpl.java:124)
    at com.googlecode.flyway.core.metadatatable.MetaDataTableImpl$1.doInTransaction(MetaDataTableImpl.java:121)
    at com.googlecode.flyway.core.util.jdbc.TransactionTemplate.execute(TransactionTemplate.java:54)
    at com.googlecode.flyway.core.metadatatable.MetaDataTableImpl.create(MetaDataTableImpl.java:121)
    at com.googlecode.flyway.core.metadatatable.MetaDataTableImpl.createIfNotExists(MetaDataTableImpl.java:134)
    at com.googlecode.flyway.core.Flyway$1.execute(Flyway.java:834)
    at com.googlecode.flyway.core.Flyway$1.execute(Flyway.java:820)
    at com.googlecode.flyway.core.Flyway.execute(Flyway.java:1259)
    at com.googlecode.flyway.core.Flyway.migrate(Flyway.java:820)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1612)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1483)
    ... 54 more
Caused by: org.h2.jdbc.JdbcSQLException: Schema "public" not found; SQL statement:
CREATE TABLE "public"."schema_version" (
    "version_rank" INT NOT NULL,
    "installed_rank" INT NOT NULL,
    "version" VARCHAR(50) NOT NULL,
    "description" VARCHAR(200) NOT NULL,
    "type" VARCHAR(20) NOT NULL,
    "script" VARCHAR(1000) NOT NULL,
    "checksum" INT,
    "installed_by" VARCHAR(30) NOT NULL,
    "installed_on" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "execution_time" INT NOT NULL,
    "success" BOOLEAN NOT NULL
) [90079-160]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:169)
    at org.h2.message.DbException.get(DbException.java:146)
    at org.h2.command.Parser.getSchema(Parser.java:613)
    at org.h2.command.Parser.getSchema(Parser.java:620)
    at org.h2.command.Parser.parseCreateTable(Parser.java:5147)
    at org.h2.command.Parser.parseCreate(Parser.java:3800)
    at org.h2.command.Parser.parsePrepared(Parser.java:324)
    at org.h2.command.Parser.parse(Parser.java:279)
    at org.h2.command.Parser.parse(Parser.java:251)
    at org.h2.command.Parser.prepareCommand(Parser.java:217)
    at org.h2.engine.Session.prepareLocal(Session.java:415)
    at org.h2.engine.Session.prepareCommand(Session.java:364)
    at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1119)
    at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:164)
    at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:152)
    at com.googlecode.flyway.core.dbsupport.JdbcTemplate.executeStatement(JdbcTemplate.java:296)
    at com.googlecode.flyway.core.dbsupport.SqlStatement.execute(SqlStatement.java:76)
    ... 71 more

所以看来,在第一个配置中,Flyway能够在medical_claims_tracker模式中创建schema_version表,但是无法找到运行测试的模式,而在第二个版本中,它甚至找不到用于创建schema_version表的“默认”模式。这是正确的,还是我的方法错了?

6 个答案:

答案 0 :(得分:12)

从我测试的结果来看,整个问题只发生在将flyway和H2与MySql兼容模式混合时(如果是MySql模式则不会发生)。它是由区分大小写不一致引起的:

    初始化期间
  1. h2创建默认架构'PUBLIC'(大写!)
  2. 当flyway尝试获取默认架构名称时,它会变为“public”(小写!)
  3. 当flyway尝试将当前架构更改为“public”(小写!)时会抛出错误。 即使将飞路模式设置为“MYSCHEMA”,在迁移过程的某个阶段,它总是会尝试更改为“公共”。
  4. 在我目前开发的应用程序中,我们使用MySql作为主数据库,使用H2进行测试。我的解决方法涉及在h2初始化期间创建'public'(小写!)模式:

    spring数据源配置:

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
     <property name="driverClassName" value="org.h2.Driver"/>
     <property name="url" value="jdbc:h2:mem:MY_APP;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:db/migration/test/init_tests.sql';"/>
     <property name="username" value="sa"/>
     <property name="password" value=""/>
    </bean>
    

    init_tests.sql:

    CREATE SCHEMA IF NOT EXISTS "public";
    

    不漂亮但是有效 - 希望有所帮助!

答案 1 :(得分:11)

来自http://www.h2database.com/javadoc/org/h2/engine/DbSettings.html

  

databaseToUpper:   数据库设置DATABASE_TO_UPPER(默认值:true)。

     

DATABASE()的数据库短名称转换为大写   功能......   将此设置为“false”是实验性的。全部设置为false时   标识符名称(表名,列名)区分大小写 ...

问题是默认情况下模式名称是大写的。

解决方案:

;DATABASE_TO_UPPER=false添加到数据库网址

答案 2 :(得分:7)

应引用init脚本中的模式名称,或者传递给Flyway的模式名称为大写。

答案 3 :(得分:2)

问题是语句中的标识符public是小写引用:

CREATE TABLE "public"...(...)

它应该是不加引号的:

CREATE TABLE public...(...)

或大写:

CREATE TABLE "PUBLIC"...(...)

H2在数据库元数据中返回小写“public”的原因是MySQL模式用于数据库URL(;MODE=MySQL)。所以使用MySQL模式可能会解决问题。

答案 4 :(得分:1)

虽然我没有使用Spring,但我遇到了类似的问题。我正在使用jOOQ + Flyway + PostgreSQL在现有设置的顶部添加H2内存数据库进行测试。

对我而言,解决方案是一系列变化:

  1. 从@ Omid的上述答案中,将;DATABASE_TO_UPPER=false添加到启动网址
  2. 从@ Tom的回答中,将架构创建添加到init SQL脚本:CREATE SCHEMA IF NOT EXISTS public;(我不需要使用反引号)。
  3. 最后在同一个脚本中,在架构创建后添加第二行SET SCHEMA public;
  4. 请注意,我无法将;SCHEMA=public添加到init网址,因为这会在创建架构之前抛出错误。可替换地:

    1. ;DATABASE_TO_UPPER=false;INIT=CREATE SCHEMA IF NOT EXISTS public;添加到启动网址。
    2. 然后将SET SCHEMA public;添加到init SQL脚本。

答案 5 :(得分:1)

以防您想尝试liquibase

我使用MySQL作为我的prod环境,h2作为我的测试环境。

使用以下内容生成jooq代码:gradle + liquibase + h2

发现这可以解决问题:

DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(new Settings()
        // make everything to uppercase 
        .withRenderNameStyle(RenderNameStyle.UPPER)
        // mapping oldSchemaName to newSchemaName
        .withRenderMapping(new RenderMapping().withSchemata(
                new MappedSchema()
                        .withInput("input_schema")
                        .withOutput("OUTPUT_SCHEMA"))
        ));

写一个配置文件,在春天为h2应用它。所以mysql配置仍然很好。

最新文档jooq-3.9: settings-name-style