【问题标题】:How to create a database with flyway?如何使用flyway创建数据库?
【发布时间】:2013-11-16 10:43:25
【问题描述】:

问题:是否可以在迁移脚本中创建一个新的数据库然后连接到它?怎么样?

我的场景: 我正在尝试在我的 Java 项目(使用 Jersey2.4 + tomcat 7 + PostgreSQL 9.3.1 + EclipseLink 的 RESTful 应用程序)中使用 flyway 来管理使用 git 的不同开发人员之间的更改。我编写了我的初始化脚本并运行它:

PGPASSWORD='123456' psql -U postgres -f migration/V1__initDB.sql

而且效果很好。问题是我无法用我的脚本创建新数据库。当我在脚本中包含以下行时:

CREATE DATABASE my_database OWNER postgres ENCODING 'UTF8';

我收到此错误:

org.postgresql.util.PSQLException: ERROR: CREATE DATABASE cannot run inside a transaction block
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1886)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:555)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:403)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:395)
    at com.googlecode.flyway.core.dbsupport.JdbcTemplate.executeStatement(JdbcTemplate.java:230)
    at com.googlecode.flyway.core.dbsupport.SqlScript.execute(SqlScript.java:89)
    at com.googlecode.flyway.core.resolver.sql.SqlMigrationExecutor.execute(SqlMigrationExecutor.java:72)
    at com.googlecode.flyway.core.command.DbMigrate$2.doInTransaction(DbMigrate.java:252)
    at com.googlecode.flyway.core.command.DbMigrate$2.doInTransaction(DbMigrate.java:250)
    at com.googlecode.flyway.core.util.jdbc.TransactionTemplate.execute(TransactionTemplate.java:56)
    at com.googlecode.flyway.core.command.DbMigrate.applyMigration(DbMigrate.java:250)
    at com.googlecode.flyway.core.command.DbMigrate.access$700(DbMigrate.java:47)
    at com.googlecode.flyway.core.command.DbMigrate$1.doInTransaction(DbMigrate.java:189)
    at com.googlecode.flyway.core.command.DbMigrate$1.doInTransaction(DbMigrate.java:138)
    at com.googlecode.flyway.core.util.jdbc.TransactionTemplate.execute(TransactionTemplate.java:56)
    at com.googlecode.flyway.core.command.DbMigrate.migrate(DbMigrate.java:137)
    at com.googlecode.flyway.core.Flyway$1.execute(Flyway.java:872)
    at com.googlecode.flyway.core.Flyway$1.execute(Flyway.java:819)
    at com.googlecode.flyway.core.Flyway.execute(Flyway.java:1200)
    at com.googlecode.flyway.core.Flyway.migrate(Flyway.java:819)
    at ir.chom.MyApp.<init>(MyApp.java:28)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at org.glassfish.hk2.utilities.reflection.ReflectionHelper.makeMe(ReflectionHelper.java:1117)
    at org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:867)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:814)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:906)
    at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:898)
    at org.glassfish.jersey.server.ApplicationHandler.createApplication(ApplicationHandler.java:300)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:279)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:302)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:167)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:349)
    at javax.servlet.GenericServlet.init(GenericServlet.java:160)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1280)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1091)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5176)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5460)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3954)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1345)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1530)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1540)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1519)
    at java.lang.Thread.run(Thread.java:724)

这似乎是使用autocommit 选项的JDBC 的问题。可以通过以下方式禁用此选项:

Connection connection = dataSource.getConnection();
Connection.setAutoCommit(false);        // Disables auto-commit.

但我不知道如何将此选项传递给 flyway 连接。另外,如果我解决了这个问题,我认为将密码传递给\c 命令会有问题。

【问题讨论】:

    标签: java database postgresql jdbc flyway


    【解决方案1】:

    我不知道这是否可以在flyway中做到。

    Flyway 旨在连接到已经存在的数据库(无论它是否为空)。将数据库创建与数据库迁移分开也是一种很好的做法。

    【讨论】:

      【解决方案2】:

      Flyway 始终在 jdbc 连接字符串中使用的数据库内运行。

      一旦连接,所有脚本都会在一个事务中运行。由于事务中不支持 CREATE DATABASE,因此您将无法完成您想要的操作。

      但是,您可以做的是创建一个架构。如果您将 Flyway 指向一个不存在的,Flyway 甚至会为您执行此操作。

      【讨论】:

      • 我最终使用默认的postgres 数据库和postgres 用户并使用CREATE SCHEMApostgres db 中创建一个新模式。稍后为了生产,我将创建其他数据库和用户。感谢您的支持,更感谢飞路。
      • 不支持数据库创建似乎有点奇怪。我不是数据库迁移方面的专家,但我希望使用一种工具来进行数据库部署。使用 Flyway,我需要单独的脚本/解决方案/工具来处理数据库部分。
      • 在 MySQL 中,database == schema(它们是相同的)所以基本上是支持的。这对我有帮助:dzone.com/articles/flyway-21-released-automatic
      • 正如@Axel 提到的,我已经从连接URL 中删除了数据库名称,并使用schemas 选项来提供数据库名称(我的是MySQL)并且Flyway 已经创建了缺失的数据库。很棒。
      • 如果我没记错的话,这意味着/要求您的用户(在其下执行其余的“常规”迁移)也具有“创建”权限;这种做法不应该受到限制吗? IE。我们不应该更喜欢在特权用户下创建模式并作为“常规”用户继续迁移吗?在那种情况下,@Gili 的解决方案将是处理这个问题的正确方法,对吧?
      【解决方案3】:

      如果你的脚本 V1 中有 schema database 创建命令,flyway 可以生成它但不能生成数据库:

      flyway -baselineOnMigrate=true -url=jdbc:mysql://localhost/ -schemas=test_db -user=root -password=root_pass -locations=filesystem:/path/to/scrips/ migrate
      

      在脚本文件中与此类似:

      DROP SCHEMA IF EXISTS `test_db` ;
      CREATE SCHEMA `test_db` COLLATE utf8_general_ci ;
      

      【讨论】:

      • 架构的创建与数据库的创建不同,尽管两者通常看起来是同义词
      • 仅供参考,关于 databaseschema... 某些数据库(例如 MySQL)仅限于单个数据库,在该数据库中您可以创建多个模式。更强大的数据库如Postgres 支持多个数据库,并且这些数据库中的每个 可以有多个架构。正式地,在 SQL 标准中,每个数据库都称为“目录”。有关详细信息,请参阅问题,What's the difference between a catalog and a schema in a relational database?
      【解决方案4】:

      这是一个对我有用的解决方法(假设使用 Maven 插件):

      为插件配置两次执行。第一次执行创建数据库。第二次执行迁移现有数据库。

          <plugin>
              <groupId>org.flywaydb</groupId>
              <artifactId>flyway-maven-plugin</artifactId>
              <version>${flyway.version}</version>
              <executions>
                  <execution>
                      <id>create-db</id>
                      <goals>
                          <goal>migrate</goal>
                      </goals>
                      <configuration>
                          <driver>org.postgresql.Driver</driver>
                          <url>jdbc:postgresql://database-server/</url>
                          <user>postgres</user>
                          <password>password</password>
                          <placeholders>
                              <DATABASE.NAME>MyDatabase</DATABASE.NAME>
                          </placeholders>
                          <locations>
                              <location>com/foo/bar/database/create</location>
                          </locations>
                      </configuration>
                  </execution>
                  <execution>
                      <id>migrate-db</id>
                      <goals>
                          <goal>migrate</goal>
                      </goals>
                      <configuration>
                          <driver>org.postgresql.Driver</driver>
                          <url>jdbc:postgresql://database-server/MyDatabase</url>
                          <user>postgres</user>
                          <password>password</password>
                          <locations>
                              <location>com/foo/bar/database/migrate</location>
                          </locations>
                      </configuration>
                  </execution>
              </executions>
              <dependencies>
                  <dependency>
                      <groupId>org.postgresql</groupId>
                      <artifactId>postgresql</artifactId>
                      <version>${postgresql.version}</version>
                  </dependency>
              </dependencies>
          </plugin>
      

      然后将V1__Created_database.sql 添加到com/foo/bar/database/create 目录。该文件包含:

      CREATE DATABASE ${DATABASE.NAME}

      【讨论】:

      • 不确定是否需要 requireThat;。如何使用 -assert (databaseName != null); ?
      • @denov 可以的。 requireThat 会给你更好的错误信息,但显然这不是必需的。
      • @Gili 也许你能帮帮我?由于某种原因,flyway-maven-plugin 无法使用此代码连接到数据库。它在执行块中找不到&lt;configuration&gt;,并出现“无法连接到数据库,请检查 url、用户、密码”。如果我只使用一个 &lt;configuration&gt; 而没有执行它就可以正常工作。
      • @EDWIN 我建议发布一个单独的问题,其中包含指向完整 pom.xml 文件的链接。您可能粘贴了正确的代码,但封闭部分是错误的。
      • 你能分享你的代码吗?我每次运行 flyway:migrate 我得到了org.flywaydb.core.api.FlywayException: Unable to connect to the database
      【解决方案5】:

      Flyway 无法为您创建数据库。 如果您没有创建架构,它可以创建架构

      flyway.schemas: schema1,schema2
      

      【讨论】:

        【解决方案6】:

        你可以试试本期的建议:https://github.com/flyway/flyway/issues/2556,在flyway中配置的mysql url中使用createDatabaseIfNotExist参数,如下:

          <groupId>org.flywaydb</groupId>
            <artifactId>flyway-maven-plugin</artifactId>
            <version>6.4.1</version>
            <configuration>
                <url>jdbc:mysql://localhost:3306/<databaseName>?createDatabaseIfNotExist=true</url>
                <user>root</user>
                <password>root</password>
            </configuration>
        

        【讨论】:

          猜你喜欢
          • 2021-10-12
          • 2011-10-02
          • 1970-01-01
          • 2019-05-21
          • 2020-12-25
          • 2015-02-22
          • 2020-03-05
          • 2013-02-13
          相关资源
          最近更新 更多