Creating DDL with spring loading using custom separator

I want to create ddl creation and removal scripts using spring boot v1.4.3 with JPA - Hibernate 5.0.11.

Most of the answers found use javax.persistence.schema-generation properties. For instance. stack overflow

The problem with this approach is that it outputs sql statements without a separator. For instance.

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

I want it to output delimited operators ;

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

But I can not find any javax.persistence.schema-generation property to configure it.

So, I was thinking of using SchemaExport from sleep mode because you can set the delimiter property . But to create a SchemaExport I need a MetadataImplementor (without an overridden api).

I can't figure out how to get the MetadataImplementor download from spring.

Does anyone know if there is

  • a javax.persistence.schema-generation property to define a delimiter
  • or how to create SchemaExport (get dependencies)
  • or has another solution?

Here is the code you can play with

 @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; } } // application.properties 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 // maven dependencies <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> 

With Hibernate 5.0

I just tried the code above with hibernate 5.0.11.Final . The only thing you have to change:

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

or, of course, let the java configuration return MetadataImplementor instead of Metadata and change the constructor parameter of ApplicationRunner .

+4
source share
2 answers

Finally, after a lot of investigation, I think I found an easy solution using public APIs. The solution I found uses hibernate 5.2 (more specific 5.2.6.Final ). But I think it can also be adapted to 5.0

Here is my java spring configuration

 @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; } } 

The java configuration creates a Metadata bean. This bean can be used in hibernate 5.2 to perform circuit generation. For instance.

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

The hibernation dialog is configured using spring boot application.properties . In my case:

 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL57InnoDBDialect 
+3
source

I found that sessionFactory contains sessionFactory values ​​such as createSQL, dropSQL, outputFile and delimiter .

enter image description here

sessionFactory as a Bean can be created this way and then available for auto-preparation:

 .... @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); } 

This is not a working solution, but can help you manually configure schemaExport using sessionFactory. I do not find a solution just to use the properties and set the separator only there. But it can be a little helper to find a working solution.

If I find more useful information, I will update my answer.

0
source

Source: https://habr.com/ru/post/1235913/


All Articles