Vlad Mihalcea

  • Home
  • Blog
  • Store
    • Books
    • Courses
    • Hypersistence Optimizer
      • Documentation
        • Installation Guide
        • User Guide
      • Examples
      • Release Notes
      • Issue Tracker
      • Trial Version
      • Full Version
    • Affiliate
  • Training
    • High-Performance Java Persistence
    • High-Performance Spring Persistence
    • High-Performance SQL
    • Spring and Hibernate 6
  • Consulting
    • Coaching
  • Tutorials
    • Hibernate
    • SQL
    • Spring
  • Newsletter
    • Subscribe
    • Videos
    • Talks

 Leave a Comment

Posted on May 2, 2017 by vladmihalcea

How to get access to database table metadata with Hibernate 5

Last modified:
Follow @vlad_mihalcea

Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?

What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?

Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.

So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!

Introduction

One of my readers has recently asked me to answer this StackOverflow question, and because the question is very interesting, I decided to turn the answer into a blog post.

In this article, I’m going to show you how you can get access to database table metadata using Hibernate 5 API.

How to get access to database table metadata with Hibernate 5@vlad_mihalceahttps://t.co/J8OxBFA0Ql pic.twitter.com/lOQgRM1H51

— Java (@java) August 14, 2019

Integrator

Hibernate is very flexible, so it defines many SPI (Service Provider Interfaces) that you can register to customize Hibernate internals. One of these interfaces is org.hibernate.integrator.spi.Integrator which is used by many technologies that integrate with Hibernate ORM, like Bean Validation, Envers or JACC Security Provider.

Using the Hibernate Integrator API, we can write our own component that captures the SessionFactory build-time metadata which, otherwise, is only available during bootstrap.

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

    public static final MetadataExtractorIntegrator INSTANCE = 
        new MetadataExtractorIntegrator();

    private Database database;

    public Database getDatabase() {
        return database;
    }

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

        database = metadata.getDatabase();
    }

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

The org.hibernate.boot.model.relational.Database is what we are interested in since it contains all the database-related metadata.

To register MetadataExtractorIntegrator with Hibernate we have two possibilities based on the bootstrap method.

Hibernate-native boostrap

If you’re using the Hibernate-native bootstrap, then you can register the Integrator with the BootstrapServiceRegistryBuilder as follows:

final BootstrapServiceRegistry bootstrapServiceRegistry = 
    new BootstrapServiceRegistryBuilder()
    .enableAutoClose()
    .applyIntegrator(MetadataExtractorIntegrator.INSTANCE)
    .build();

final StandardServiceRegistry serviceRegistry = 
    new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
    .applySettings(properties())
    .build();

JPA boostrap

If you’re using the JPA bootstrap, then you can register the Integrator with the BootstrapServiceRegistryBuilder as follows:

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

Integrator integrator = integrator();
if (integrator != null) {
    configuration.put("hibernate.integrator_provider", 
        (IntegratorProvider) () -> Collections.singletonList(
            MetadataExtractorIntegrator.INSTANCE
        )
    );
}

EntityManagerFactory entityManagerFactory = new EntityManagerFactoryBuilderImpl(
    new PersistenceUnitInfoDescriptor(persistenceUnitInfo), 
    configuration
)
.build();

To see how you can set the hibernate.integrator_provider configuration property when using Spring with JPA or Spring with Hibernate, check out this article.

Domain Model

Assuming we have the following database tables mapped by our JPA application:

Database tables

When running the following test case:

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

Hibernate generates the following output:

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)
]

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

Hibernate is highly customizable, and the Integrator SPI allows you to get access to the Database metadata which you can later inspect from your enterprise application.

Follow @vlad_mihalcea
Transactions and Concurrency Control eBook
Vlad Mihalcea Consulting
High-Performance Java Persistence rocks!
Hypersistence Optimizer rocks!

Related

 Category: Hibernate      Tags: Database, hibernate, metadata, table, Training, Tutorial

← The best way to do batch processing with JPA and Hibernate
How to install DB2 Express-C on Docker and set up the JDBC connection properties →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Let’s connect
  • X
  • YouTube
  • LinkedIn
  • Email
  • Facebook
  • Amazon
  • GitHub
Find Article
Book
High-Performance Java Persistence Book
Video Courses
High-Performance Java Persistence Video Course High-Performance SQL Video Course
Sponsored
Training
Training logo
Hypersistence Optimizer
Hypersistence Optimizer
Free eBook - Transactions and Concurrency Control
Tutorials
  • Hibernate
  • SQL
  • Spring
  • Git
  • FlexyPool
Social Media
  • Twitter
  • Facebook
  • YouTube
  • GitHub
  • LinkedIn
About
  • About
  • FAQ
  • Archive
  • Privacy Policy
  • Terms of Service
  • Cookie Policy (EU)
Meta
  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

Vlad Mihalcea

Powered by WordPress.com.

Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
View preferences
  • {title}
  • {title}
  • {title}
 

Loading Comments...