2016-01-20 53 views
0

两年前我用工作的一个项目:汽车没有数据库连接生成JPA 2.1注解的实体类的数据模式

  • 春天4.0.3.RELEASE
  • JPA 2.0
  • 冬眠4.2 .7.Final
  • 的Java 1.6.x版

这个项目有一个Maven任务Hibernate3中,Maven的插件,它允许我们生成一个数据库模式w ^没有任何连接到数据库(MySQL)。

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

  • 的Java 1.8
  • JPA 2.1
  • 春天4.2.4.RELEASE
  • 冬眠5.0.6.Final

我理解hibernate3-maven-plugin在JPA 2.1和hibernate> 4.3上不起作用。

我发现的所有解决方案都需要连接到数据库。例如:Auto generate data schema from JPA annotated entity classes

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

+0

这有什么,在这里做弹簧,请删除我碰到这个解决方案附带的标签 – chokdee

回答

0

我能够与JPA2.1混合你的Hibernate解决方案:

我现在能够从persistence.xml中

这种方式添加的实体类,我可以生成SQL文件在实体所在的罐子外面。

这是一个临时的解决方案,直到休眠解决这个bug

感谢您的帮助。

/** 
* 
*/ 
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(); 
    } 

} 
0

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

对于使用H2数据库为例(需要H2,scannotation,休眠和共同1-10):

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<String> 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)); 
       } 
      } 
     } 
} 
} 

可以在一个单元测试要这样做或创建注释处理器。

+0

,但我不知道,如果生成的SQL是100U Mysql的标准。你知道我在哪里可以找到这个信息吗? –

+0

这取决于Mysql Dialect类如何实现。我用它为postgresql,它工作正常。 – JEY

3

我遵循你的想法使用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); 
     } 
    } 
+0

没有分号是已知的错误:https://hibernate.atlassian.net/browse/HHH-10278 –

+0

奇怪的是,应用程序。不存在无'System.exit(0)' –

+0

最简单的解决方法是以下内容: //生成与分号SQL - 解决方法HHH-10278 字符串systemLineSeparator = System.getProperty( “line.separator”); System.setProperty(“line.separator”,';'+ systemLineSeparator); Persistence.generateSchema(persistenceUnitName,persistenceProperties); – blacky