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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33700123/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:00:45  来源:igfitidea点击:

Hibernate 5. Generate SQL DDL into file

javahibernate

提问by felix

I tried using this class:

我尝试使用这个类:

Hibernate/JPA: Check generated sql before updating DB Schema (like .NET EF migrations)

Hibernate/JPA:在更新数据库架构之前检查生成的 sql(如 .NET EF 迁移)

I have the following code:

我有以下代码:

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<Class> 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<Class> collectClasses(String packageName, File directory) throws ClassNotFoundException {
        List<Class> 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;
        }
    }
}

And I get the following error:

我收到以下错误:

Exception in thread "main" java.lang.UnsupportedOperationException: Attempt to use unsupported SchemaExport constructor accepting org.hibernate.cfg.Configuration; one of the forms accepting org.hibernate.boot.spi.MetadataImplementor should be used instead at org.hibernate.tool.hbm2ddl.SchemaExport.(SchemaExport.java:250) at cu.x.util.SchemaGenerator.generate(SchemaGenerator.java:116) at cu.x.util.SchemaGenerator.main(SchemaGenerator.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

线程“main”中的异常 java.lang.UnsupportedOperationException:尝试使用不支持的 SchemaExport 构造函数接受 org.hibernate.cfg.Configuration;接受 org.hibernate.boot.spi.MetadataImplementor 的形式之一应该在 org.hibernate.tool.hbm2ddl.SchemaExport.(SchemaExport.java:250) 在 cu.x.util.SchemaGenerator.generate(SchemaGenerator.java) 中使用:116) at cu.x.util.SchemaGenerator.main(SchemaGenerator.java:32) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun。 com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) 处的 java.lang.reflect.Method.invoke(Method.java:497) 处的reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

I change my code with the following:

我使用以下内容更改我的代码:

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

But it generates an empty .sql file. I'm using annotated classes. What could be happening?

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

回答by felix

Apparently the Configuration class can not be used. We must use the MetadataSources class to add the annotated classes.

显然不能使用 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);
}

回答by Bertrand Cedric

The solution of felix don't work anymore on hibernate 5.2

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

here is a version who si compatible private void generate(Class dialect, String directory, String... packagesName) throws Exception {

这是一个兼容 private void generate(Class dialect, String directory, String...packagesName) 的版本抛出异常 {

    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<TargetType> enumSet = EnumSet.of(TargetType.STDOUT);
    export.execute(enumSet, SchemaExport.Action.CREATE, metadataImplementor);
}

回答by Jakub Kubrynski

Normally tools that dumps the JPA schema are based on SchemaExport tool, which reads only the static metadata.

通常转储 JPA 模式的工具基于 SchemaExport 工具,它只读取静态元数据。

There is a Maven/Gradle plugin https://github.com/Devskiller/jpa2ddlwhich generates the JPA schema. In includes all properties, namings strategies, user types, etc.

有一个 Maven/Gradle 插件https://github.com/Devskiller/jpa2ddl可以生成 JPA 模式。In 包括所有属性、命名策略、用户类型等。

You can also use it to generate automated schema migrations for Flyway.

您还可以使用它为 Flyway 生成自动模式迁移。

回答by Vladimir

I wrote a class for generating sql script depends on packages with entites.

我写了一个类来生成 sql 脚本取决于带有实体的包。

Used version of hibernate is '5.3.7.Final'

使用的休眠版本是“5.3.7.Final”

public final class HibernateExporter {

    private static final Logger LOG = LoggerFactory.getLogger(HibernateExporter.class);
    private static final String OUTPUT_FILE = "schema.sql";
    private static final String DIALECT = "org.hibernate.dialect.H2Dialect";

    private List<String> entityPackages;

    private HibernateExporter(List<String> entityPackages) {
        this.entityPackages = entityPackages;
    }

    public static void main(String[] args) {
        final List<String> entityPackages = Collections.singletonList("pakage.with.entites");

        HibernateExporter exporter = new HibernateExporter(entityPackages);
        exporter.export();
    }

    private void export() {
        SchemaExport export = new SchemaExport();
        export.setOutputFile(OUTPUT_FILE);
        export.setFormat(true);
        export.setDelimiter(";");
        EnumSet<TargetType> types = EnumSet.of(TargetType.SCRIPT);
        Metadata metadata = createMetadataSources().buildMetadata();
        export.execute(types, Action.CREATE, metadata);
    }

    private MetadataSources createMetadataSources() {
        MetadataSources metadata = new MetadataSources(
                new StandardServiceRegistryBuilder()
                        .applySetting("hibernate.dialect", DIALECT)
                        .build());

        for (String entityPackage : entityPackages) {
            final Reflections reflections = new Reflections(entityPackage);
            for (Class<?> cl : reflections.getTypesAnnotatedWith(MappedSuperclass.class)) {
                metadata.addAnnotatedClass(cl);
                LOG.info(String.format("Mapped = %s", cl.getName()));
            }
            for (Class<?> cl : reflections.getTypesAnnotatedWith(Entity.class)) {
                metadata.addAnnotatedClass(cl);
                LOG.info(String.format("Mapped = %s", cl.getName()));
            }
        }
        return metadata;
    }
}