2017-04-25 38 views
5

Aktualnie aktualizuję wersję Hibernuj do najnowszej wersji 5.2.10. Zastąpiłem mój kod w HibernateUtil dla stworzenia SessionFactory.Ulepszenie hibernacji do wersji 5.2 - Utworzenie fabryki sesji i zastąpienie obiektu PersistentClass w celu uzyskania właściwości klasy obiektu

4.3.11.Final (Poprzedni):

public class HibernateUtil { 
    private HibernateUtil() {} 

    private static SessionFactory sessionFactory; 

    private static Configuration configuration; 

    public static Configuration getConfiguration() { 
     return configuration; 
    } 
    private static SessionFactory buildSessionFactory() { 
     try { 
        if(sessionFactory == null) { 
         configuration = new Configuration(); 
         configuration.configure("hibernate.cfg.xml"); 
         ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() 
           .applySettings(configuration.getProperties()).build(); 
         sessionFactory = configuration 
           .buildSessionFactory(serviceRegistry); 
        } 
      return sessionFactory; 
     } 
     catch (Throwable ex) { 
      throw new ExceptionInInitializerError(ex); 
     } 

    } 
    public static SessionFactory getSessionFactory() { 
     return buildSessionFactory(); 
    } 

    public static Session getSession() { 
     Session hibernateSession = getSessionFactory().getCurrentSession(); 
     return hibernateSession; 
     } 

    public static void shutdown() { 
     getSessionFactory().close(); 
    } 
} 

5.2.10 ostateczna (Nowe):

public class HibernateUtil { 
    private static StandardServiceRegistry registry; 
    private static SessionFactory sessionFactory; 

    public static SessionFactory getSessionFactory() { 
     return buildSessionFactory(); 
    } 

    public static SessionFactory buildSessionFactory() { 
    if (sessionFactory == null) { 
     try { 
     registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build(); 
     MetadataSources sources = new MetadataSources(registry); 
     Metadata metadata = sources.getMetadataBuilder().build(); 
     sessionFactory = metadata.getSessionFactoryBuilder().build(); 
     } catch (Exception e) { 
     e.printStackTrace(); 
     shutdown(); 
     } 
    } 
    return sessionFactory; 
    } 

public static Session getSession() { 
     Session hibernateSession = getSessionFactory().getCurrentSession(); 
     return hibernateSession; 
     } 

    public static void shutdown() { 
    if (registry != null) { 
     StandardServiceRegistryBuilder.destroy(registry); 
    } 
    } 
} 

Teraz mam metodę, która będzie pobierał mi listę nazw kolumn, przekazując nazwę tabeli DB jako ciąg znaków. Zrobiłem to tak, zanim w 4.3.11.Final:

public static List<String> getColumnNames(String tableName) { 

     List<String> columnList=null; 

     Map<String, ClassMetadata> map = HibernateUtil.getSessionFactory().getAllClassMetadata(); 
     Iterator<Entry<String, ClassMetadata>> itr = map.entrySet().iterator(); 

     while(itr.hasNext()){ 

      ClassMetadata classMetaData = itr.next().getValue(); 
      AbstractEntityPersister aep = (AbstractEntityPersister) classMetaData; 

      if(aep.getTableName().split("\\.")[1].equalsIgnoreCase(tableName)){ 

       columnList = new ArrayList<String>(); 
       String[] propertyNames = classMetaData.getPropertyNames(); 

       for(String property : propertyNames){ 
         try { 
          PersistentClass persistentClass = HibernateUtil .getConfiguration().getClassMapping(classMetaData.getEntityName()); 
          String clmName = ((Column) persistentClass.getProperty(property).getColumnIterator().next()).getName(); 
          columnList.add(clmName); 
         } catch(NoSuchElementException e){ 
          log.error("Element not found idenfied as : "+property); 
         } catch(Exception e){ 
          log.error(e.getMessage()); 
         } 
       } 
       break; 
      } 
     } 

     return columnList; 
    } 

Teraz po aktualizacji pokazuje metoda getAllClassMetadata jako przestarzałe i jestem w obliczu trudności, aby uzyskać obiekt PersistentClass. Widziałem podobne pytanie here, ale nie mogłem dokładnie znaleźć rozwiązania. Której części mojego obecnego kodu muszę zmienić, aby moja metoda getColumnNames() działała dokładnie tak, jak poprzednio. Odesłałem dokumentację i powiedziałem, aby zamiast tego użyć EntityManagerFactory.getMetamodel(), ale nie mogę znaleźć odpowiednich przykładów referencyjnych tego samego. Czy będę musiał zmienić mechanizm tworzenia sesji SessionFactory?

Odpowiedz

2

W końcu zrobiłem to dziękuję słowu Vlada. Wziąłem kod integratora bez żadnych zmian i zmodyfikowałem moją metodę HibernateUtil i getColumns(). Więc tutaj jest mój kod:

SessionFactory utworzenia:

public class HibernateUtil { 

    private static final SessionFactory sessionFactory = buildSessionFactory(); 

    public static SessionFactory getSessionFactory() { 
     return buildSessionFactory(); 
    } 

    private static SessionFactory buildSessionFactory() { 
     final BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().enableAutoClose() 
       .applyIntegrator(MetadataExtractorIntegrator.INSTANCE).build(); 

     final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).configure().build(); 
     return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory(); 
    } 

    public static Session getSession() { 
     Session hibernateSession = getSessionFactory().getCurrentSession(); 
     return hibernateSession; 
    } 

    public static void shutdown() { 
     getSessionFactory().close(); 
    } 
} 

Metadata Extractor (Get nazwy kolumn):

public static List<String> getColumnNames(String tableName) { 

    List<String> columnList = new ArrayList<>(); 

    for (Namespace namespace : MetadataExtractorIntegrator.INSTANCE.getDatabase().getNamespaces()) { 
     for (Table table : namespace.getTables()) { 
      if (table.getName().equalsIgnoreCase(lookupTableName)) { 
       Iterator<Column> iterator = table.getColumnIterator(); 
       while (iterator.hasNext()) { 
        columnList.add(iterator.next().getName()); 
       } 
       break; 
      } 
     } 
     if (!columnList.isEmpty()) 
      break; 
    } 
    return columnList; 
} 
2

Świetne pytanie. W rzeczywistości podobało mi się tak bardzo, że napisałem an article about it.

Po pierwsze, musimy utworzyć nową Integrator:

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

    public static final MetadataExtractorIntegrator INSTANCE = 
     new MetadataExtractorIntegrator(); 

    private Database database; 

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

     database = metadata.getDatabase(); 
    } 

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

    } 

    public Database getDatabase() { 
     return database; 
    } 
} 

Następnie można po prostu skonfigurować Hibernacja go używać.

Jeśli używasz bootstrap mechanizm hibernacji, można dodać go tak:

final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder(); 
bsrb.enableAutoClose(); 

Integrator integrator = integrator(); 
if (integrator != null) { 
    bsrb.applyIntegrator(integrator); 
} 

final BootstrapServiceRegistry bsr = bsrb.build(); 

final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(bsr); 

Jeśli ładowania z JPA, to można to zrobić w następujący sposób:

protected EntityManagerFactory newEntityManagerFactory() { 
    PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo(
     getClass().getSimpleName() 
    ); 

    Map<String, Object> configuration = new HashMap<>(); 


    configuration.put("hibernate.integrator_provider", 
     (IntegratorProvider)() -> Collections.singletonList(MetadataExtractorIntegrator.INSTANCE) 
    ); 

    EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl(
      new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration 
    ); 
    return entityManagerFactoryBuilder.build(); 
} 

teraz, gdy uruchomiony następujący test:

for(Namespace namespace : MetadataExtractorIntegrator.INSTANCE 
    .getDatabase() 
    .getNamespaces()) { 

    for(Table table : namespace.getTables()) { 
     LOGGER.info("Table {} has the following columns: {}", 
      table, 
      StreamSupport.stream(
       Spliterators.spliteratorUnknownSize( 
        table.getColumnIterator(), 
        Spliterator.ORDERED 
       ), 
       false 
      ) 
      .collect(Collectors.toList()) 
     ); 
    } 
} 

wyjść Hibernate wszystkich aktualnie odwzorowany t ables w dzienniku:

Table org.hibernate.mapping.Table(post) has the following columns: [ 
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(title), 
    org.hibernate.mapping.Column(version) 
] 
Table org.hibernate.mapping.Table(post_comment) has the following columns: [ 
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(review), 
    org.hibernate.mapping.Column(version), 
    org.hibernate.mapping.Column(post_id) 
] 
Table org.hibernate.mapping.Table(post_details) has the following columns: [ 
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(created_by), 
    org.hibernate.mapping.Column(created_on), 
    org.hibernate.mapping.Column(version) 
] 
Table org.hibernate.mapping.Table(post_tag) has the following columns: [ 
    org.hibernate.mapping.Column(post_id), 
    org.hibernate.mapping.Column(tag_id) 
] 
Table org.hibernate.mapping.Table(tag) has the following columns: [ 
    org.hibernate.mapping.Column(id), 
    org.hibernate.mapping.Column(name), 
    org.hibernate.mapping.Column(version) 
] 

To wszystko!

+0

Dzięki @Vlad za odpowiedź.Czy będę musiał zastąpić mój kod klasy HibernateUtil, o którym wspomniałem powyżej, z sugerowanym przez ciebie mechanizmem ładowania początkowego Hibernate? Czy możesz wyjaśnić nieco więcej na ten temat, ponieważ ten mechanizm jest dla mnie stosunkowo nowy. Jak odczytuje konfigurację jako der nie ma hibernate.cfg.xml w twoim kodzie. Integrator Integrator = integrator() odnosi się do jakiej metody integratora? Również w metodzie testowej namespace.getTables() jest częścią org.hibernate.boot.relational.Namespace. Jak mogę uzyskać nazwę kolumny? –

+0

Sprawdź [ten artykuł] (https://vladmihalcea.com/2017/05/02/how-to-get-access-to-database-table-metadata-with-hibernate-5/), aby zobaczyć, że możesz również uzyskać dostęp do kolumn. Możesz rozwidlić [moja książka, High-Performance Java Persistence, repozytorium GitHub] (https://github.com/vladmihalcea/high-performance-java-persistence/blob/master/core/src/test/java/com/vladmihalcea /book/hpjp/hibernate/metadata/MetadataTest.java), aby zobaczyć, jak to działa, a także bootstrap. –