【问题标题】:Where did Configuration.generateSchemaCreationScript() go in Hibernate 5Configuration.generateSchemaCreationScript() 在 Hibernate 5 中去了哪里
【发布时间】:2015-11-17 15:00:17
【问题描述】:

在 Hibernate 4.x 中,我曾经生成和导出带注释实体中定义的模式,如下所示(使用 Spring 在类路径上查找带注释的实体):

Connection connection = 
    DriverManager.getConnection("jdbc:h2:mem:jooq-meta-extensions", "sa", "");

Configuration configuration = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

// [...] adding annotated classes to Configuration here...

configuration.generateSchemaCreationScript(
    Dialect.getDialect(configuration.getProperties()));
SchemaExport export = new SchemaExport(configuration, connection);
export.create(true, true);

这在 Hibernate 5.0 中不再有效:

除了:

相当多的方法已从配置中删除

使用 Hibernate 5.0 基于一组带注释的实体在现有 JDBC 连接上生成和导出数据库的正确方法是什么? (纯基于 JPA 的解决方案也可以)

(请注意,仅删除对 generateSchemaCreationScript() 的调用似乎可行,但我希望确保正确处理)

【问题讨论】:

  • 感谢您的编辑,@NeilStockton。如果 Hibernate 实现的纯基于 JPA 的解决方案是可能的,我也会把它作为答案。
  • 您的意思是为 persistence.xml 中的类所需的模式创建一个 DDL 文件? (因为我不使用 Hibernate,所以不知道这些方法是什么)。这不是 javax.persistence.schema-generation.scripts.action 和 javax.persistence.schema-generation.scripts.create-target 的属性吗?
  • 问题实际上是“使用 Hibernate 5.0 基于一组带注释的实体生成导出数据库的正确方法是什么?(纯基于 JPA 的解决方案也可以)"

标签: java jpa configuration hbm2ddl hibernate-5.x


【解决方案1】:

感谢VladGunnar 的回答,我已经设法通过新的配置API 来生成具有以下内容的等效导出逻辑。当然,历史表明这个 API 会再次崩溃,所以一定要选择合适的版本:

休眠 5.2:

MetadataSources metadata = new MetadataSources(
    new StandardServiceRegistryBuilder()
        .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
        .applySetting("javax.persistence.schema-generation-connection", connection)
        .build());

// [...] adding annotated classes to metadata here...
metadata.addAnnotatedClass(...);

SchemaExport export = new SchemaExport();
export.create(EnumSet.of(TargetType.DATABASE), metadata.buildMetadata());

休眠 5.2(无警告):

上面会产生一些讨厌的警告,可以忽略:

2016 年 10 月 20 日下午 2:57:16 org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator 启动服务
警告:HHH000181:没有遇到适当的连接提供程序,假设应用程序将提供连接
2016 年 10 月 20 日下午 2:57:16 org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator 启动服务
警告:HHH000342:无法获得查询元数据的连接:应用程序必须提供 JDBC 连接

...或者您通过将以下ConnectionProvider 破解到设置中来解决它们(我认为它不应该是必需的)

        .applySetting(AvailableSettings.CONNECTION_PROVIDER, new ConnectionProvider() {
            @Override
            public boolean isUnwrappableAs(Class unwrapType) {
                return false;
            }
            @Override
            public <T> T unwrap(Class<T> unwrapType) {
                return null;
            }
            @Override
            public Connection getConnection() {
                return connection; // Interesting part here
            }
            @Override
            public void closeConnection(Connection conn) throws SQLException {}

            @Override
            public boolean supportsAggressiveRelease() {
                return true;
            }
        })

休眠 5.0:

MetadataSources metadata = new MetadataSources(
    new StandardServiceRegistryBuilder()
        .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
        .build());

// [...] adding annotated classes to metadata here...
metadata.addAnnotatedClass(...);

SchemaExport export = new SchemaExport(
    (MetadataImplementor) metadata.buildMetadata(),
    connection // pre-configured Connection here
);
export.create(true, true);

休眠 4:

提醒一下,这是在 Hibernate 4 中的工作方式:

Configuration configuration = new Configuration()
    .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

// [...] adding annotated classes to metadata here...
configuration.addAnnotatedClass(...);

configuration.generateSchemaCreationScript(
    Dialect.getDialect(configuration.getProperties()));
SchemaExport export = new SchemaExport(configuration, connection);
export.create(true, true);

【讨论】:

  • 为什么休眠需要连接?在测试设置中,根据已知的良好版本检查生成的架构时不需要它。
  • @gkephorus:我不确定你的意思。在我的例子中,模式是由一些 DDL 语句编写的,而 Hibernate 用于生成实体类(另见问题)。当然,还有其他设置,但这个问题是关于这个特定用例的。
  • 我的立场是正确的,我应该提出一个新问题。对不起。 (这个问题的答案是正确的)
  • 卢卡斯,感谢您的解决方案。但这似乎不适用于 HIbernate 5.2,因为我无法将任何内容传递给 Schemaexport。你遇到过这个问题吗? ——
  • @FreakyThommi:好的,我已经对他们的最新版本进行了逆向工程。现在似乎又可以工作了……答案已更新
【解决方案2】:

SchemaExportTask 中可以找到新的SchemaExport 初始化示例:

final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build();

final MetadataSources metadataSources = new MetadataSources( bsr );
final StandardServiceRegistryBuilder ssrBuilder = new StandardServiceRegistryBuilder( bsr );

if ( configurationFile != null ) {
    ssrBuilder.configure( configurationFile );
}
if ( propertiesFile != null ) {
    ssrBuilder.loadProperties( propertiesFile );
}
ssrBuilder.applySettings( getProject().getProperties() );

for ( String fileName : getFiles() ) {
    if ( fileName.endsWith(".jar") ) {
        metadataSources.addJar( new File( fileName ) );
    }
    else {
        metadataSources.addFile( fileName );
    }
}


final StandardServiceRegistryImpl ssr = (StandardServiceRegistryImpl) ssrBuilder.build();
final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder( ssr );

ClassLoaderService classLoaderService = bsr.getService( ClassLoaderService.class );
if ( implicitNamingStrategy != null ) {
    metadataBuilder.applyImplicitNamingStrategy(
            (ImplicitNamingStrategy) classLoaderService.classForName( implicitNamingStrategy ).newInstance()
    );
}
if ( physicalNamingStrategy != null ) {
    metadataBuilder.applyPhysicalNamingStrategy(
            (PhysicalNamingStrategy) classLoaderService.classForName( physicalNamingStrategy ).newInstance()
    );
}

return new SchemaExport( (MetadataImplementor) metadataBuilder.build() )
    .setHaltOnError( haltOnError )
    .setOutputFile( outputFile.getPath() )
    .setDelimiter( delimiter );

当然,你可以根据自己的需要来定制。

【讨论】:

  • 好点。这当然可行,但在我看来,创建了许多不必要的样板类型。我想知道是否真的需要所有这些......
  • 看来是逃不过MetadataImplementor对象构造,确实笨重。反正这么多间接层很容易迷路,这里只是为了配置。
  • 那就需要一个 Jira 问题。
【解决方案3】:

新的引导 API 允许进行许多自定义,但假设您不需要这些,最短的调用应该是这样的,为服务注册表和所有设置应用默认值:

Metadata metadata = new MetadataSources()
    .addAnnotatedClass( MyEntity.class )
    .build();

new SchemaExport( (MetadataImplementor) metadata )
    .setOutputFile( "my-statements.ddl" )
    .create( Target.NONE );

更新:提供应用配置属性的示例

有几种方法可以为连接 URL、方言等注入属性。例如你可以提供一个文件hibernate.properties,或者你使用一个定制了所需设置的服务注册表:

StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
    .applySetting( "hibernate.connection.url", "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" )
    .build();

Metadata metadata = new MetadataSources( registry )
    .build();

【讨论】:

  • 假设我想要Target.BOTH,我需要connectionhibernate.dialect 配置(如问题所示)。那些会去哪里?
  • 更新了答案以包含指定配置属性的示例
  • 如果我显得挑剔,我很抱歉 :) 但我已经更新了问题中的一个重要细节 - 我有一个独立的 JDBC Connection 来执行 DDL,这一点很重要(对我来说)。我不希望 Hibernate 管理连接,在这种特殊情况下......
  • 然后调用构造函数SchemaExport(MetadataImplementor, Connection)
  • 感谢您的更新。我真的必须指定方言or I get this exception。我想知道如果它提供给SchemaExport,Hibernate 是否无法从 JDBC 连接中猜出方言?我现在已经记录了我正在寻找的具体解决方案in an additional answer
【解决方案4】:

我用 hibernate 5.4.9.Final 以这种方式导出它:

import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;

import java.util.EnumSet;

public class ExportSchema {
    public static void main(String[] args) {
        final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySetting("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
                .build();
        final Metadata metadata = new MetadataSources(serviceRegistry)
                .addAnnotatedClass(...)
                .buildMetadata();
        new SchemaExport()
                .setFormat(true)
                .setDelimiter(";")
                .setOutputFile("schema.sql")
                .execute(EnumSet.of(TargetType.SCRIPT), SchemaExport.Action.CREATE, metadata);
    }
}

【讨论】:

    【解决方案5】:

    如果使用 JPA 2.1+ - 有一个非常简单的内置可能性来生成 ddl。只需设置以下 jpa 属性,就会创建 ddl 文件。使用 Spring Boot,可以使用这些特定的配置选项编写一个单独的主类。

    JPA 2.1+

    javax.persistence.schema-generation.scripts.action=drop-and-create
    javax.persistence.schema-generation.scripts.create-target=create.ddl
    javax.persistence.schema-generation.scripts.drop-target=drop.ddl
    

    使用 JPA 2.1+ 的 Spring Boot

    schemagenerator.properties(放入资源文件夹):

    spring.jpa.properties.javax.persistence.schema-generation.scripts.action=drop-and-create
    spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.ddl
    spring.jpa.properties.javax.persistence.schema-generation.scripts.drop-target=drop.ddl
    flyway.enabled=false // in case you use flyway for db maintenance
    

    Spring Boot SchemaGenerator:

    public class SchemaGenerator {
        public static void main(String[] args) throws Exception {
            SpringApplication.run(Application.class, new String[]{"--spring.config.name=schemagenerator"}).close();
        }
    }
    

    【讨论】:

    • 谢谢,但是在这个问题中,我明确地在寻找“在现有 JDBC 连接上生成和导出数据库的正确方法是什么”的解决方案跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-02
    • 1970-01-01
    • 2012-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多