如何使用 Hibernate 5 访问数据库表元数据

在本文中,我们简单介绍如何在hibernate中访问数据库表的元数据。

Integrator

Hibernate 非常灵活,因此它定义了许多 SPI(服务提供者接口),您可以注册这些 SPI 以自定义 Hibernate 内部结构。其中一个接口是 org.hibernate.integrator.spi.Integrator,它被许多与 Hibernate ORM 集成的技术使用,比如 Bean Validation、Envers 或 JACC Security Provider。

使用 Hibernate Integrator API,我们可以编写自己的组件来捕获 SessionFactory 构建时元数据,否则该元数据仅在引导期间可用。

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) {
    }
}

我们感兴趣的是 org.hibernate.boot.model.relational.Database,因为它包含所有与数据库相关的元数据。

要向 Hibernate 注册 MetadataExtractorIntegrator,我们有两种基于引导方法的可能性。

Hibernate-native boostrap

如果您使用的是 Hibernate-native bootstrap,那么您可以使用 BootstrapServiceRegistryBuilder 注册 Integrator,如下所示:

final BootstrapServiceRegistry bootstrapServiceRegistry =
    new BootstrapServiceRegistryBuilder()
    .enableAutoClose()
    .applyIntegrator(MetadataExtractorIntegrator.INSTANCE)
    .build();
 
final StandardServiceRegistry serviceRegistry =
    new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
    .applySettings(properties())
    .build();

JPA boostrap

如果您使用的是 JPA 引导程序,则可以使用 BootstrapServiceRegistryBuilder 注册 Integrator,如下所示:

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

用一个例子来测试下:

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

以上代码会将持久化单元中的实体对应的表结构都打印出来,感兴趣的可以试试。

另一个例子如下:

Metadata metadata = MetadataExtractorIntegrator.INSTANCE.getMetadata();
 
for ( PersistentClass persistentClass : metadata.getEntityBindings()) {
 
    Table table = persistentClass.getTable();
     
    LOGGER.info( "Entity: {} is mapped to table: {}",
                 persistentClass.getClassName(),
                 table.getName()
    );
 
    for(Iterator propertyIterator = persistentClass.getPropertyIterator();
            propertyIterator.hasNext(); ) {
        Property property = (Property) propertyIterator.next();
         
        for(Iterator columnIterator = property.getColumnIterator();
                columnIterator.hasNext(); ) {
            Column column = (Column) columnIterator.next();
             
            LOGGER.info( "Property: {} is mapped on table column: {} of type: {}",
                         property.getName(),
                         column.getName(),
                         column.getSqlType()
            );
        }
    }
}

以上代码会将持久化单元中的实体到表结构的映射打印出来。

版权声明:著作权归作者所有。

thumb_up 0 | star_outline 0 | textsms 0