Hibernate 5.将SQL DDL生成到文件中

我尝试使用这个类:

Hibernate / JPA:在更新DB Schema之前检查生成的sql(如.NET EF迁移)

我有以下代码:

package com.mypackage.jpa.util; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.hibernate.cfg.Configuration; import org.hibernate.tool.hbm2ddl.SchemaExport; public class SchemaGenerator { private Configuration cfg; public static void main(String[] args) throws Exception { File f = new File("."); String directory = f.getAbsoluteFile() + "/src/main/resources/ddl/generated/"; String packageName[] = { "com.mypackage.jpa", "com.mypackage.jpa.legacy", "com.mypackage.jpa.local", "com.mypackage.jpa.local.impl" }; SchemaGenerator gen = new SchemaGenerator(packageName); gen.generate(Dialect.MYSQL, directory); } @SuppressWarnings("rawtypes") public SchemaGenerator(String[] packagesName) throws Exception { cfg = new Configuration(); cfg.setProperty("hibernate.hbm2ddl.auto", "create"); for (String packageName : packagesName) { for (Class clazz : getClasses(packageName)) { cfg.addAnnotatedClass(clazz); } } } @SuppressWarnings("rawtypes") private List getClasses(String packageName) throws Exception { File directory = null; try { ClassLoader cld = getClassLoader(); URL resource = getResource(packageName, cld); directory = new File(resource.getFile()); } catch (NullPointerException ex) { throw new ClassNotFoundException(packageName + " (" + directory + ") does not appear to be a valid package"); } return collectClasses(packageName, directory); } private ClassLoader getClassLoader() throws ClassNotFoundException { ClassLoader cld = Thread.currentThread().getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } return cld; } private URL getResource(String packageName, ClassLoader cld) throws ClassNotFoundException { String path = packageName.replace('.', '/'); URL resource = cld.getResource(path); if (resource == null) { throw new ClassNotFoundException("No resource for " + path); } return resource; } @SuppressWarnings("rawtypes") private List collectClasses(String packageName, File directory) throws ClassNotFoundException { List classes = new ArrayList(); if (directory.exists()) { String[] files = directory.list(); for (String file : files) { if (file.endsWith(".class")) { // removes the .class extension classes.add(Class.forName(packageName + '.' + file.substring(0, file.length() - 6))); } } } else { throw new ClassNotFoundException(packageName + " is not a valid package"); } return classes; } private void generate(Dialect dialect, String directory) { cfg.setProperty("hibernate.dialect", dialect.getDialectClass()); SchemaExport export = new SchemaExport(cfg); export.setDelimiter(";"); export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql"); export.setFormat(true); export.execute(true, false, false, false); } private static enum Dialect { ORACLE("org.hibernate.dialect.Oracle10gDialect"), MYSQL("org.hibernate.dialect.MySQLDialect"), HSQL( "org.hibernate.dialect.HSQLDialect"), H2("org.hibernate.dialect.H2Dialect"); private String dialectClass; private Dialect(String dialectClass) { this.dialectClass = dialectClass; } public String getDialectClass() { return dialectClass; } } } 

我收到以下错误:

线程“main”中的exceptionjava.lang.UnsupportedOperationException:尝试使用不受支持的SchemaExport构造函数接受org.hibernate.cfg.Configuration; 其中一个接受org.hibernate.boot.spi.MetadataImplementor的表单应该在cu.x.util.SchemaGenerator.generate(SchemaGenerator.java)的org.hibernate.tool.hbm2ddl.SchemaExport。(SchemaExport.java:250)中使用。 :116)位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)的sun.reflect.NativeMethodAccessorImpl.invoke0(本地方法)中的cu.x.util.SchemaGenerator.main(SchemaGenerator.java:32)。在com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)的java.lang.reflect.Method.invoke(Method.java:497)中反映.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

我用以下代码更改了我的代码:

 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build(); MetadataImplementor metadataImplementor = (MetadataImplementor) new MetadataSources(serviceRegistry).buildMetadata(); SchemaExport export = new SchemaExport(metadataImplementor); 

但它会生成一个空的.sql文件。 我正在使用带注释的类。 可能会发生什么?

显然,不能使用Configuration类。 我们必须使用MetadataSources类来添加带注释的类。

 private void generate(Dialect dialect, String directory, String[] packagesName) throws Exception { MetadataSources metadata = new MetadataSources( new StandardServiceRegistryBuilder() .applySetting("hibernate.dialect", dialect.getDialectClass()) .build()); for (String packageName : packagesName) { log.info("packageName: " + packageName); for (Class clazz : getClasses(packageName)) { log.info("Class: " + clazz); metadata.addAnnotatedClass(clazz); } } SchemaExport export = new SchemaExport( (MetadataImplementor) metadata.buildMetadata() ); export.setDelimiter(";"); export.setOutputFile(directory + "ddl_" + dialect.name().toLowerCase() + ".sql"); export.setFormat(true); export.execute(true, false, false, false); } 

felix的解决方案在hibernate 5.2上不再起作用了

这是一个兼容private void generate的版本(Class dialect,String directory,String … packagesName)throws Exception {

  MetadataSources metadata = new MetadataSources( new StandardServiceRegistryBuilder() .applySetting("hibernate.dialect", dialect.getName()) .build()); for (String packageName : packagesName) { LOG.info("packageName: " + packageName); for (Class clazz : getClasses(packageName)) { LOG.info("Class: " + clazz); metadata.addAnnotatedClass(clazz); } } MetadataImplementor metadataImplementor = (MetadataImplementor) metadata.buildMetadata(); SchemaExport export = new SchemaExport(); export.setDelimiter(";"); String filename = directory + "ddl_" + dialect.getSimpleName().toLowerCase() + ".sql"; export.setOutputFile(filename); export.setFormat(true); //can change the output here EnumSet enumSet = EnumSet.of(TargetType.STDOUT); export.execute(enumSet, SchemaExport.Action.CREATE, metadataImplementor); }