从JPA 2.1带注释的实体类自动生成数据模式,无需数据库连接

两年前,我正在使用以下项目开展项目:

  • spring4.0.3.RELEASE
  • jpa 2.0
  • hibernate 4.2.7.Final
  • java 1.6.X

这个项目有一个maven任务hibernate3-maven-plugin,它允许我们在没有任何数据库连接(MySQL)的情况下生成数据库模式。

现在我们正在升级这个项目:

  • java 1.8
  • jpa 2.1
  • spring4.2.4.RELEASE
  • hibernate 5.0.6.Final

据我所知,hibernate3-maven-plugin在JPA 2.1和hibernate> 4.3上不起作用。

我发现的所有解决方案都需要连接到数据库。

例如: 从JPA带注释的实体类中自动生成数据模式 。

有谁知道如何离线生成数据库模式? 我所拥有的是一个persistence.xml,列出了所有的Entity类。

我遵循你的想法,使用h2与Mysql方言,但使用JPA Persistence.generateSchema(...)

除了所有命令都没有被半列分隔外,它确实有效…

如何使用JPA 2.1完成此操作?

否则我会切换到你的解决方案。

 import java.util.Properties; import javax.persistence.Persistence; import javax.persistence.PersistenceException; import org.hibernate.jpa.AvailableSettings; /** * Generate DDL with hibernate 4+/5: * http://stackoverflow.com/questions/27314165/generate-ddl-script-at-maven-build-with-hibernate4-jpa-2-1/27314166#27314166 * @author dmary * */ public class Jpa21SchemaExport { /** * */ public Jpa21SchemaExport() { // TODO Auto-generated constructor stub } /** * @param args */ public static void main(String[] args) { execute(args[0], args[1]); System.exit(0); } public static void execute(String persistenceUnitName, String destination) { System.out.println("Generating DDL create script to : " + destination); final Properties persistenceProperties = new Properties(); // XXX force persistence properties : remove database target persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, ""); persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_DATABASE_ACTION, "none"); // XXX force persistence properties : define create script target from metadata to destination // persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SCHEMAS, "true"); persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_ACTION, "create"); persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_CREATE_SOURCE, "metadata"); persistenceProperties.setProperty(AvailableSettings.SCHEMA_GEN_SCRIPTS_CREATE_TARGET, destination); persistenceProperties.setProperty(AvailableSettings.JDBC_DRIVER,"org.h2.Driver"); persistenceProperties.setProperty(AvailableSettings.JDBC_URL, "jdbc:h2:mem:export"); persistenceProperties.setProperty(AvailableSettings.JDBC_USER, "sa"); persistenceProperties.setProperty(AvailableSettings.JDBC_PASSWORD, ""); persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.DIALECT, "com.wiztivi.sdk.persistence.MySQL5InnoDBUTF8Dialect"); try { Persistence.generateSchema(persistenceUnitName, persistenceProperties); } catch (PersistenceException pe) { System.err.println("DDL generation failed: "); pe.printStackTrace(System.err); } } 

另一个问题是,您可以使用hbm2ddl和嵌入式数据库来提供连接。

例如使用H2数据库(需要h2,scannotation,hibernate和common-io):

 package com.stackoverflow; import java.io.File; import java.io.FileWriter; import java.io.InputStream; import java.net.URL; import java.util.Set; import javax.persistence.Entity; import org.apache.commons.io.IOUtils; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.connection.DriverManagerConnectionProvider; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.scannotation.AnnotationDB; public class ExportShema { private static final String OUTPUT_SQL_FILE = "target/database.sql"; private static final String INIT_FILE = "init.sql"; private static final String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; private static final String DB_USERNAME = "sa"; private static final String DB_PASSWORD = ""; private static final File HBM_DIRECTORY = new File("src/main/resources/com/stackoverflow/domain/"); public static void main(final String[] args) throws Exception { final Configuration cfg = new Configuration(); cfg.setProperty(Environment.CONNECTION_PROVIDER, DriverManagerConnectionProvider.class.getName()); //for postgrest schema cfg.setProperty(Environment.DIALECT, PostgreSQLDialect.class.getName()); cfg.setProperty(Environment.URL, DB_URL); cfg.setProperty(Environment.USER, DB_USERNAME); cfg.setProperty(Environment.PASS, DB_PASSWORD); //If you have HBM + annotated class cfg.addDirectory(HBM_DIRECTORY); final AnnotationDB db = new AnnotationDB(); db.scanArchives(new URL("file:target/classes/")); final Set clazzNames = db.getAnnotationIndex().get(Entity.class.getName()); for (final String clazzName : clazzNames) { cfg.addAnnotatedClass(Class.forName(clazzName)); } final SchemaExport exporter = new SchemaExport(cfg); exporter.setOutputFile(OUTPUT_SQL_FILE); exporter.setDelimiter(";"); exporter.setFormat(true); exporter.create(false, true); try (final InputStream init_file = ExportShema.class.getResourceAsStream(INIT_FILE)) { if (init_file != null) { final File output = new File(OUTPUT_SQL_FILE); try (final FileWriter fw = new FileWriter(output, true)) { final String eol = System.getProperty("line.separator"); fw.append(eol + eol); fw.append(IOUtils.toString(init_file)); } } } } } 

您可以在unit testing中执行此操作或创建注释处理器。

我能够将您的Hibernate解决方案与JPA2.1混合使用:

我现在能够从persistence.xml添加实体类

这样我就可以在实体所在的jar外部生成SQl文件。

这是一个临时解决方案,直到hibernate修复此错误

谢谢你的帮助。

 /** * */ package com.stackoverflow.common.util.schema; import java.io.IOException; import java.util.Properties; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl; import org.hibernate.jpa.AvailableSettings; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.dialect.MySQL5InnoDBDialect; /** * */ public class JPA21Hibernate5ExportSchema { private static final String JDBC_DRIVER = "org.h2.Driver"; private static final String JDBC_URL = "jdbc:h2:mem:export;DB_CLOSE_DELAY=-1"; private static final String JDBC_USERNAME = "sa"; private static final String JDBC_PASSWORD = ""; /** * */ public JPA21Hibernate5ExportSchema() { } public static void main(String[] args) { try { JPA21Hibernate5ExportSchema hes = new JPA21Hibernate5ExportSchema(); hes.export(args[0], args[1]); System.exit(0); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } public void export(String persistenceUnitName, String sqlFile) throws IOException, ClassNotFoundException { final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); final MetadataSources metadataSources = new MetadataSources(bsr); final StandardServiceRegistryBuilder srrBuilder = new StandardServiceRegistryBuilder(bsr) .applySetting(Environment.CONNECTION_PROVIDER, DriverManagerConnectionProviderImpl.class.getName()) .applySetting(Environment.DIALECT, MySQL5InnoDBDialect.class.getName()) .applySetting(Environment.URL, JDBC_URL).applySetting(Environment.USER, JDBC_USERNAME) .applySetting(Environment.PASS, JDBC_PASSWORD); // Use the persistence metamodel to retrieve the Entities classes Metamodel metamodel = this.getMetamodel(persistenceUnitName); for (final ManagedType managedType : metamodel.getManagedTypes()) { metadataSources.addAnnotatedClass(managedType.getJavaType()); } final StandardServiceRegistry ssr = (StandardServiceRegistry) srrBuilder.build(); final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(ssr); final SchemaExport exporter = new SchemaExport((MetadataImplementor) metadataBuilder.build()); exporter.setOutputFile(sqlFile); exporter.setDelimiter(";"); exporter.setFormat(true); exporter.create(false, true); } /** * Retrieve the JPA metamodel from the persistence unit name * * @param persistenceUnitName * @return */ private Metamodel getMetamodel(String persistenceUnitName) { final Properties persistenceProperties = new Properties(); persistenceProperties.setProperty(AvailableSettings.JDBC_DRIVER, JDBC_DRIVER); persistenceProperties.setProperty(AvailableSettings.JDBC_URL, JDBC_URL); persistenceProperties.setProperty(AvailableSettings.JDBC_USER, "sa"); persistenceProperties.setProperty(AvailableSettings.JDBC_PASSWORD, ""); persistenceProperties.setProperty(org.hibernate.cfg.AvailableSettings.DIALECT, MySQL5InnoDBDialect.class.getName()); final EntityManagerFactory emf = Persistence.createEntityManagerFactory(persistenceUnitName, persistenceProperties); return emf.getMetamodel(); } }