복붙노트

[SPRING] 봄 부팅시 모든 테이블 메타 데이터를 얻는 방법 - JPA - 최대 절전 모드?

SPRING

봄 부팅시 모든 테이블 메타 데이터를 얻는 방법 - JPA - 최대 절전 모드?

나는 내 스키마에 동적으로 존재하는 모든 테이블의 META 정보를 얻을 필요가있다. 메타 정보는 테이블, 엔티티, 컬럼 이름 등이다.

나는 다음 튜토리얼을 따라 갔다.

https://vladmihalcea.com/how-to-get-the-entity-mapping-to-database-table-binding-metadata-from-hibernate/

위의 링크에서 MetadataExtractorIntegrator.java라는 Integrator를 만들었습니다.

package com.test.ttv;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

public class MetadataExtractorIntegrator implements org.hibernate.integrator.spi.Integrator {

    public static final MetadataExtractorIntegrator INSTANCE = new MetadataExtractorIntegrator();

    private Database database;

    private Metadata metadata;

    public Database getDatabase() {
        return database;
    }

    public Metadata getMetadata() {
        return metadata;
    }

    @Override
    public void integrate(
            Metadata metadata,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {

        this.database = metadata.getDatabase();
        this.metadata = metadata;

    }

    @Override
    public void disintegrate(
        SessionFactoryImplementor sessionFactory,
        SessionFactoryServiceRegistry serviceRegistry) {

    }
}

그리고 구성에 따라 내 응용 프로그램에 등록하려고합니다.

application.yml

jpa:
  properties:
    hibernate.integrator_provider: com.test.ttv.MetadataExtractorIntegrator

그리고 빌드를 시작하는 동안 다음과 같은 예외가 발생합니다.

Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.hibernate.jpa.boot.spi.IntegratorProvider

더 많은 StackTrace

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to org.hibernate.jpa.boot.spi.IntegratorProvider
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1710) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1085) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:858) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140) ~[spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234) [spring-boot-2.0.0.RELEASE.jar:2.0.0.RELEASE]
        at testtest(Test.java:31) [main/:na]
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.hibernate.jpa.boot.spi.IntegratorProvider
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.buildBootstrapServiceRegistry(EntityManagerFactoryBuilderImpl.java:339) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:196) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.<init>(EntityManagerFactoryBuilderImpl.java:164) ~[hibernate-core-5.2.14.Final.jar:5.2.14.Final]
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:51) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:388) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:377) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
        ... 16 common frames omitted

아무도 나를이 문제를 해결하는 데 도움이 될 수 있습니까 ?? 감사

해결법

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

    1.스프링 부트에서 spring.jpa.properties는 Map 을 가리키므로 String 값만 포함 할 수 있습니다.

    스프링 부트에서 spring.jpa.properties는 Map 을 가리키므로 String 값만 포함 할 수 있습니다.

    그러나 Hibernate에서 EntityManagerFactoryBuilderImpl이 hibernate.integrator_provider를 읽을 때 클래스 이름이 아닌 IntegratorProvider의 인스턴스를 찾을 것으로 예상되므로 예외가 발생합니다.

    그러나 HibernatePropertiesCustomizer를 구현하는 Bean을 추가하여 IntegrationProvider 인스턴스를 Hibernate 속성에 추가 할 수있다.

    @Component
    public class HibernateConfig implements HibernatePropertiesCustomizer {
    
        @Override
        public void customize(Map<String, Object> hibernateProperties) {
            hibernateProperties.put("hibernate.integrator_provider",
                    (IntegratorProvider) () -> Collections.singletonList(MetadataExtractorIntegrator.INSTANCE));
        }
    }
    

    이 저장소에 작업 예제를 만들었습니다.

  2. ==============================

    2.Spring Boot 1.5.x를 사용한다면 "HibernatePropertiesCustomizer"가 존재하지 않습니다.

    Spring Boot 1.5.x를 사용한다면 "HibernatePropertiesCustomizer"가 존재하지 않습니다.

    여기서 사용할 수있는 솔루션을 찾았습니다. 여기서는 통합자를 사용할 수 없지만 모든 이벤트 수신기를 하나씩 추가 할 수 있습니다. 다음은 내 코드 코드입니다.

    public class RootAwareInsertEventListener implements PersistEventListener {
    
        public static final RootAwareInsertEventListener INSTANCE = new RootAwareInsertEventListener();
    
        @Override
        public void onPersist(PersistEvent event) throws HibernateException {
            final Object entity = event.getObject();
    
            if (entity instanceof RootAware) {
                RootAware rootAware = (RootAware) entity;
                Object root = rootAware.getRoot();
                event.getSession().lock(root, LockMode.OPTIMISTIC_FORCE_INCREMENT);
    
                log.info("Incrementing {} entity version because a {} child entity has been inserted",
                        root, entity);
            }
        }
    
        @Override
        public void onPersist(PersistEvent event, Map createdAlready)
                throws HibernateException {
            onPersist(event);
        }
    }
    
    @Component
    public class HibernateListenerConfigurer {
    
        @PersistenceUnit
        private EntityManagerFactory emf;
    
        @PostConstruct
        protected void init() {
            SessionFactoryImpl sessionFactory = emf.unwrap(SessionFactoryImpl.class);
            EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
            registry.getEventListenerGroup(EventType.PERSIST).appendListener(RootAwareInsertEventListener.INSTANCE);
            registry.getEventListenerGroup(EventType.FLUSH_ENTITY).appendListener(RootAwareUpdateAndDeleteEventListener.INSTANCE);
    
        }
    }
    
  3. from https://stackoverflow.com/questions/51501405/how-to-get-the-all-table-metadata-in-spring-boot-jpa-hibernate by cc-by-sa and MIT license