无法在 Spring 应用程序中使用 Flyway 1.6 进行迁移

Posted

技术标签:

【中文标题】无法在 Spring 应用程序中使用 Flyway 1.6 进行迁移【英文标题】:Unable migrate using Flyway 1.6 in Spring application 【发布时间】:2012-04-30 04:32:12 【问题描述】:

我有 Roo 生成的 Spring MVC 应用程序使用 Hibernate 连接到 PostgreSQL。我正在尝试将 Flyway 1.6 作为 bean 集成到 Spring 应用程序上下文中。 “某些事情阻止”迁移被执行,并且我在由 Hibernate 元数据验证引起的上下文初始化时出错。 使用 Flyway 1.6 Maven 插件(clean、init、migrate)执行迁移没有问题。

Flyway 1.5(以前的版本)的集成工作得很好。

我应该怎么做才能使 Flyway 1.6 集成迁移工作? 我应该提供什么额外的配置?

环境:Ubuntu 11.10、Springsource Tool Suite 2.9.1 (Eclipse 3.7.2)、OpenJDK 6b23、Tomcat 7.0.23、PostgreSQL 8.4.9/9.1、Spring 3.0/3.1、Hibernate 3.6.4.Final、PostgreSQL Native驱动程序 8.4 JDBC3/4 build 702。

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
...
<dependencies>
    ...
    <dependency>
        <groupId>com.googlecode.flyway</groupId>
        <artifactId>flyway-core</artifactId>
        <version>1.6</version>
        <classifier/>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>com.googlecode.flyway</groupId>
            <artifactId>flyway-maven-plugin</artifactId>
            <version>1.6</version>
            <configuration>
                <driver>org.postgresql.Driver</driver>
                <url>jdbc:postgresql://localhost:5432/library</url>
                <baseDir>db/migration</baseDir>
                <user>library</user>
                <password>library</password>
            </configuration>
        </plugin>
        ...
    </plugins>
</build>
</project>

database.properties:

database.password=library
database.url=jdbc\:postgresql\://localhost\:5432/library
database.username=library
database.driverClassName=org.postgresql.Driver

persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.hbm2ddl.auto" value="validate"/>
        <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
        <property name="hibernate.connection.charSet" value="UTF-8"/>
    </properties>
</persistence-unit>
</persistence>

Spring上下文配置:

<beans xmlns="http://www.springframework.org/schema/beans" ...>
<context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
<context:spring-configured/>
<context:component-scan base-package="edu.sandbox.library">
    <context:exclude-filter expression=".*_Roo_.*" type="regex"/>
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
    <property name="driverClassName" value="$database.driverClassName"/>
    <property name="url" value="$database.url"/>
    <property name="username" value="$database.username"/>
    <property name="password" value="$database.password"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testOnReturn" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis" value="1800000"/>
    <property name="numTestsPerEvictionRun" value="3"/>
    <property name="minEvictableIdleTimeMillis" value="1800000"/>
    <property name="validationQuery" value="SELECT version();"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="flyway" id="entityManagerFactory">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean class="com.googlecode.flyway.core.Flyway" id="flyway" init-method="migrate">
    <property name="dataSource" ref="dataSource"/>
</bean>
</beans>

日志:

...
INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@19d03a4e: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,org.springframework.context.config.internalBeanConfigurerAspect,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,dataSource,transactionManager,org.springframework.transaction.config.internalTransactionAspect,entityManagerFactory,flyway]; root of factory hierarchy
DEBUG com.googlecode.flyway.core.dbsupport.DbSupportFactory - Database: PostgreSQL
DEBUG com.googlecode.flyway.core.Flyway - Schema: public
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'persistenceUnit'
...
INFO  org.hibernate.tool.hbm2ddl.DatabaseMetadata - table not found: book
INFO  org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@43a4181c: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,org.springframework.context.config.internalBeanConfigurerAspect,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,dataSource,transactionManager,org.springframework.transaction.config.internalTransactionAspect,entityManagerFactory,flyway]; root of factory hierarchy
ERROR org.springframework.web.context.ContextLoader - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in file [/.../applicationContext.xml]: Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in file [/.../applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: persistenceUnit] Unable to build EntityManagerFactory
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
...

【问题讨论】:

【参考方案1】:

看来您可能会遇到与此相同的问题:https://github.com/flyway/flyway/issues/107

请给附带的 jar 一个测试。如果它也适用于您,我会在接下来的几天内将其发布为 1.6.1。

【讨论】:

flyway-core-1.7-SNAPSHOT.jar 一切正常。非常感谢。期待 Flyway 的下一个版本——一个非常有价值的数据库迁移工具。祝你好运! 感谢您的反馈!总是让我开心 :-) 1.6.1 已经修复。【参考方案2】:

将尾随 / 添加到 baseDir 属性值 (as mentioned) 似乎是 Flyway 1.6 的解决方法:

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

迁移按预期运行,产生以下日志:

...
DEBUG com.googlecode.flyway.core.dbsupport.DbSupportFactory - Database: PostgreSQL
DEBUG com.googlecode.flyway.core.Flyway - Schema: public
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Found resource: db/migration/V1__initial.sql
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Found resource: db/migration/V1__initial.sql
DEBUG com.googlecode.flyway.core.util.ClassPathScanner - Scanning directory: file:/home/developer/projects/sandbox/t7-work/webapps/library/WEB-INF/classes/db/migration/
DEBUG com.googlecode.flyway.core.migration.sql.SqlScript - Found statement at line 17: CREATE TABLE public.schema_version (
...
DEBUG com.googlecode.flyway.core.migration.sql.SqlStatement - Executing SQL: CREATE INDEX schema_version_current_version_index ON public.schema_version (current_version)
INFO  com.googlecode.flyway.core.metadatatable.MetaDataTable - Metadata table created: schema_version (Schema: public)
INFO  com.googlecode.flyway.core.migration.DbMigrator - Current schema version: null
INFO  com.googlecode.flyway.core.migration.DbMigrator - Migrating to version 1
...
INFO  com.googlecode.flyway.core.migration.DbMigrator - Successfully applied 1 migration (execution time 00:00.161s).
...

【讨论】:

以上是关于无法在 Spring 应用程序中使用 Flyway 1.6 进行迁移的主要内容,如果未能解决你的问题,请参考以下文章

无法将docker Spring-Boot应用程序与docker-compose中的mysql容器和flyway连接起来

将 Flyway 设置为在 Spring Boot 中使用不同的环境

使用 Spring Boot 进行 Flyway 修复

在 Spring Boot 应用程序中使用 Flyway 进行多数据源迁移

如何一起使用Spring启动,JOOQ和Flyway?

使用 Flyway 和 Spring Boot 在 docker testcontainers 环境中迁移模式