복붙노트

[SPRING] 사용자 정의 구분 기호를 사용하여 봄 부팅으로 DDL 생성

SPRING

사용자 정의 구분 기호를 사용하여 봄 부팅으로 DDL 생성

JPA - Hibernate 5.0.11과 함께 봄 부팅 v1.4.3을 사용하여 ddl 스크립트 생성 및 삭제를 생성하고 싶습니다.

대부분의 답변은 javax.persistence.schema 생성 속성을 사용합니다. 예 : https://stackoverflow.com/a/36966419/974186

이 방법의 문제점은 구분 기호없이 SQL 문을 출력한다는 것입니다. 예 :

create table ... (...)
create table ... (...)

구분 기호를 사용하여 명령문을 출력하고 싶습니다.

create table ... (...);
create table ... (...);

하지만 javax.persistence.schema-generation 속성을 찾을 수 없습니다.

그래서 당신이 구분 기호 속성을 설정할 수 있기 때문에 최대 절전 모드에서 SchemaExport를 사용하려고 생각했습니다. 하지만 SchemaExport를 만들려면 MetadataImplementor (비 deprected api)가 필요합니다.

스프링 부트에서 MetadataImplementor를 얻는 방법을 알아낼 수 없습니다.

누구든지 알 수 있습니까?

다음은 함께 연주 할 수있는 코드입니다.

@SpringBootApplication
@ComponentScan(basePackageClasses = Application.class)
@EntityScan(basePackageClasses = User.class)
public class Application {

    @Bean
    public ApplicationRunner getApplicationRunner() {
        return new ApplicationRunner() {

            public void run(ApplicationArguments args) throws Exception {
                // MetadataImplementor metadataImplementor = ???;
                // new SchemaExport(metadataImplementor);
            }
        };
    }

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(Application.class);
        application.run(args);
    }

}
@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
@Entity
public class Person {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}
spring.jpa.properties.javax.persistence.schema-generation.create-source=metadata
spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
<properties>
    <spring.boot.version>1.4.3.RELEASE</spring.boot.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring.boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>   

최대 절전 모드 5.0

난 그냥 최대 절전 모드 5.0.11과 위의 코드를 시도. 최종. 네가 변해야 만하는 것은

SchemaExport schemaExport = new SchemaExport((MetadataImplementor) metadata);
schemaExport.setDelimiter(";");
schemaExport.setFormat(false);
schemaExport.setOutputFile(dropAndCreateDdlFile.getAbsolutePath());

schemaExport.execute(true, false, false, false);

또는 물론 자바 설정이 Metadata 대신 MetadataImplementor를 반환하고 ApplicationRunner 생성자 param을 변경하도록 할 수 있습니다.

해결법

  1. ==============================

    1.마지막으로 많은 조사가 끝나면 공개 API를 사용하는 쉬운 솔루션을 발견했다고 생각합니다. 내가 찾은 해결책은 최대 절전 모드 5.2 (더 구체적인 5.2.6. 최종)를 사용합니다. 그러나 나는 또한 5.0에 적용될 수 있다고 생각한다.

    마지막으로 많은 조사가 끝나면 공개 API를 사용하는 쉬운 솔루션을 발견했다고 생각합니다. 내가 찾은 해결책은 최대 절전 모드 5.2 (더 구체적인 5.2.6. 최종)를 사용합니다. 그러나 나는 또한 5.0에 적용될 수 있다고 생각한다.

    여기 내 스프링 자바 구성입니다

    @Configuration
    @AutoConfigureAfter({ HibernateJpaAutoConfiguration.class })
    public class HibernateJavaConfig {
    
        @ConditionalOnMissingBean({ Metadata.class })
        @Bean
        public Metadata getMetadata(StandardServiceRegistry standardServiceRegistry,
                PersistenceUnitInfo persistenceUnitInfo) {
            MetadataSources metadataSources = new MetadataSources(standardServiceRegistry);
    
            List<String> managedClassNames = persistenceUnitInfo.getManagedClassNames();
            for (String managedClassName : managedClassNames) {
                metadataSources.addAnnotatedClassName(managedClassName);
            }
    
            Metadata metadata = metadataSources.buildMetadata();
            return metadata;
        }
    
        @ConditionalOnMissingBean({ StandardServiceRegistry.class })
        @Bean
        public StandardServiceRegistry getStandardServiceRegistry(JpaProperties jpaProperties) {
            StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder();
    
            Map<String, String> properties = jpaProperties.getProperties();
            ssrb.applySettings(properties);
    
            StandardServiceRegistry ssr = ssrb.build();
            return ssr;
        }
    
        @ConditionalOnMissingBean({ PersistenceUnitInfo.class })
        @Bean
        public PersistenceUnitInfo getPersistenceUnitInfo(EntityScanPackages entityScanPackages) {
            List<String> packagesToScan = entityScanPackages.getPackageNames();
    
            DefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager();
    
            String[] packagesToScanArr = (String[]) packagesToScan.toArray(new String[packagesToScan.size()]);
            persistenceUnitManager.setPackagesToScan(packagesToScanArr);
            persistenceUnitManager.afterPropertiesSet();
    
            PersistenceUnitInfo persistenceUnitInfo = persistenceUnitManager.obtainDefaultPersistenceUnitInfo();
            return persistenceUnitInfo;
        }
    
    }
    

    Java 구성은 Metadata Bean을 작성합니다. 이 빈은 스키마 생성을 실행하기 위해 hibernate 5.2에서 사용될 수있다. 예 :

    @Component
    public class GenerateDDLApplicationRunner implements ApplicationRunner {
    
        private Metadata metadata;
    
        public GenerateDDLApplicationRunner(Metadata metadata) {
            this.metadata = metadata;
        }
    
        public void run(ApplicationArguments args) throws Exception {
            File dropAndCreateDdlFile = new File("drop-and-create.ddl");
            deleteFileIfExists(dropAndCreateDdlFile);
    
            SchemaExport schemaExport = new SchemaExport();
            schemaExport.setDelimiter(";");
            schemaExport.setFormat(false);
            schemaExport.setOutputFile(dropAndCreateDdlFile.getAbsolutePath());
    
            schemaExport.execute(EnumSet.of(TargetType.SCRIPT), Action.BOTH, metadata);
        }
    
        private void deleteFileIfExists(File dropAndCreateDdlFile) {
            if (dropAndCreateDdlFile.exists()) {
                if (!dropAndCreateDdlFile.isFile()) {
                    String msg = MessageFormat.format("File is not a normal file {0}", dropAndCreateDdlFile);
                    throw new IllegalStateException(msg);
                }
    
                if (!dropAndCreateDdlFile.delete()) {
                    String msg = MessageFormat.format("Unable to delete file {0}", dropAndCreateDdlFile);
                    throw new IllegalStateException(msg);
                }
            }
        }
    
    }
    

    Hibernate dialect는 spring boot application.properties를 사용하여 설정된다. 나의 경우에는:

    spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect
    
  2. ==============================

    2.내가 알게 된 것은 sessionFactory가 createSQL, dropSQL, outputFile 및 delimiter와 같은 schemaExport 값을 보유한다는 것입니다.

    내가 알게 된 것은 sessionFactory가 createSQL, dropSQL, outputFile 및 delimiter와 같은 schemaExport 값을 보유한다는 것입니다.

    Bean으로서의 sessionFactory는 이와 같이 생성 될 수 있고 autowiring을 위해 사용할 수 있습니다 :

    ....
    
    @Autowired
    private EntityManagerFactory entityManagerFactory;
    
    @Bean
    public SessionFactory sessionFactory() {
        if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
            throw new NullPointerException("factory is not a hibernate factory");
        }
        return entityManagerFactory.unwrap(SessionFactory.class);
    }
    

    이것은 작동하는 해결책은 아니지만 sessionFactory를 사용하여 schemaExport를 수동으로 구성하는 데 도움이 될 수 있습니다. 나는 단지 속성을 사용하고 거기에 구분 기호를 설정하기위한 해결책을 찾지 못한다. 그러나 작업 솔루션을 찾는 데 약간의 도우미가 될 수 있습니다.

    보다 유용한 정보를 찾으면 답을 업데이트 할 것입니다.

  3. ==============================

    3.그것은 아마도 해결 방법이지만 내 경우에는 프로젝트를 빌드하는 동안 세미콜론을 추가하는 것으로 충분합니다. Maven 플러그인을 사용하여이를 수행 할 수 있습니다 (예 :

    그것은 아마도 해결 방법이지만 내 경우에는 프로젝트를 빌드하는 동안 세미콜론을 추가하는 것으로 충분합니다. Maven 플러그인을 사용하여이를 수행 할 수 있습니다 (예 :

    <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.6.0</version>
                    <executions>
                        <execution>
                            <id>add-semicolon-to-sql-file</id>
                            <phase>generate-resources</phase>
                            <goals>
                                <goal>exec</goal>
                            </goals>
                            <configuration>
                                <executable>sed</executable>
                                <arguments>
                                    <argument>-i</argument>
                                    <argument>/;$/!s/$/;/</argument>
                                    <argument>src/main/resources/db/migration/V1__init.sql</argument>
                                </arguments>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
    
  4. ==============================

    4.René에서 스프링 부트 2에서 작동하도록 솔루션을 수정했습니다. 버전 2.0.4로 테스트되었습니다.

    René에서 스프링 부트 2에서 작동하도록 솔루션을 수정했습니다. 버전 2.0.4로 테스트되었습니다.

    @Configuration
    @AutoConfigureAfter({ HibernateJpaAutoConfiguration.class })
    public class HibernateMetadataBean {
    
        @ConditionalOnMissingBean({ Metadata.class })
        @Bean
        public Metadata getMetadata(StandardServiceRegistry standardServiceRegistry,
                                    PersistenceUnitInfo persistenceUnitInfo) {
            MetadataSources metadataSources = new MetadataSources(standardServiceRegistry);
    
            List<String> managedClassNames = persistenceUnitInfo.getManagedClassNames();
            for (String managedClassName : managedClassNames) {
                metadataSources.addAnnotatedClassName(managedClassName);
            }
    
            return metadataSources.buildMetadata();
        }
    
        @ConditionalOnMissingBean({ StandardServiceRegistry.class })
        @Bean
        public StandardServiceRegistry getStandardServiceRegistry(JpaProperties jpaProperties) {
            StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder();
    
            Map<String, String> properties = jpaProperties.getProperties();
            ssrb.applySettings(properties);
    
            return ssrb.build();
        }
    
        @ConditionalOnMissingBean({ PersistenceUnitInfo.class })
        @Bean
        public PersistenceUnitInfo getPersistenceUnitInfo(BeanFactory beanFactory) {
            List<String> packagesToScan = EntityScanPackages.get(beanFactory).getPackageNames();
            if (packagesToScan.isEmpty() && AutoConfigurationPackages.has(beanFactory)) {
                packagesToScan = AutoConfigurationPackages.get(beanFactory);
            }
    
            DefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager();
    
            String[] packagesToScanArr = StringUtils.toStringArray(packagesToScan);
            persistenceUnitManager.setPackagesToScan(packagesToScanArr);
            persistenceUnitManager.afterPropertiesSet();
    
            return persistenceUnitManager.obtainDefaultPersistenceUnitInfo();
        }
    
    }
    
  5. ==============================

    5.당신은 다음의 Hibernate 속성을 설정하려고 시도 할 수있다.

    당신은 다음의 Hibernate 속성을 설정하려고 시도 할 수있다.

    spring.jpa.properties.hibernate.hbm2ddl.delimiter=;
    
    #in addition to the other standard JPA properties you refered to, namely:
    spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
    spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
    

    이 기능은 Spring Boot 2.1.2.RELEASE +에서 Hibernate 버전 (5.3.7.Final) 프로젝트와 동일한 기능을 필요로하는 곳에서 작업하는 것으로 나타났습니다.

    그것은 당신의별로 다르지 않은 Hibernate 환경에서 잘 작동 할 것입니다.

    주제가 약간 벗어나지 만, 내가 가지고있는 한가지 문제 : Hibernate는 create.sql에 추가합니다. 파일 내용을 바꿀 수있는 방법을 찾았습니다.

  6. from https://stackoverflow.com/questions/41832183/generate-ddl-with-spring-boot-using-a-custom-delimiter by cc-by-sa and MIT license