Configuration.generateSchemaCreationScript() 在 Hibernate 5 中去了哪里
Posted
技术标签:
【中文标题】Configuration.generateSchemaCreationScript() 在 Hibernate 5 中去了哪里【英文标题】:Where did Configuration.generateSchemaCreationScript() go in 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 中不再有效:
Configuration.generateSchemaCreationScript()
不再存在
SchemaExport(configuration, connection)
构造函数现已弃用
除了:
相当多的方法已从配置中删除
使用 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 的解决方案也可以)" 【参考方案1】:感谢Vlad 和Gunnar 的回答,我已经设法通过新的配置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 s-s-rBuilder = new StandardServiceRegistryBuilder( bsr );
if ( configurationFile != null )
s-s-rBuilder.configure( configurationFile );
if ( propertiesFile != null )
s-s-rBuilder.loadProperties( propertiesFile );
s-s-rBuilder.applySettings( getProject().getProperties() );
for ( String fileName : getFiles() )
if ( fileName.endsWith(".jar") )
metadataSources.addJar( new File( fileName ) );
else
metadataSources.addFile( fileName );
final StandardServiceRegistryImpl s-s-r = (StandardServiceRegistryImpl) s-s-rBuilder.build();
final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder( s-s-r );
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
,我需要connection
和hibernate.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 连接上生成和导出数据库的正确方法是什么”的解决方案跨度>以上是关于Configuration.generateSchemaCreationScript() 在 Hibernate 5 中去了哪里的主要内容,如果未能解决你的问题,请参考以下文章