当前位置: 首页 > 面试题库 >

带有Hibernate 5和Spring 4的程序化SchemaExport / SchemaUpdate

赵驰
2023-03-14
问题内容

在Spring 4和Hibernate 4中,我可以使用Reflection通过以下代码从当前环境中获取Hibernate Configuration对象:

@Autowired LocalContainerEntityManagerFactoryBean lcemfb;

EntityManagerFactoryImpl emf = (EntityManagerFactoryImpl) lcemfb.getNativeEntityManagerFactory();
SessionFactoryImpl sf = emf.getSessionFactory();
SessionFactoryServiceRegistryImpl serviceRegistry = (SessionFactoryServiceRegistryImpl) sf.getServiceRegistry();
Configuration cfg = null;

try {
    Field field = SessionFactoryServiceRegistryImpl.class.getDeclaredField("configuration");
    field.setAccessible(true);
    cfg = (Configuration) field.get(serviceRegistry);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    e.printStackTrace();
}

SchemaUpdate update = new SchemaUpdate(serviceRegistry, cfg);

使用Hibernate 5时,我必须使用some
MetadataImplementor,这些对象似乎都不可用。我还试图用MetadataSourcesserviceRegistry。但是它确实说这是错误的一种ServiceRegistry

还有其他方法可以使它正常工作吗?


问题答案:

我想加总Aviad的答案,以按照OP的要求完成它。

内部:

为了获得MetadataImplementor的实例,解决方法是通过Java的ServiceLoader工具注册SessionFactoryBuilderFactory的实例。然后,在引导hibernate模式时,MetadataImplementor会使用其自身的实例调用此注册服务的getSessionFactoryBuilder方法。代码参考如下:

  1. 服务加载
  2. 调用getSessionFactoryBuilder

因此,最终要获得MetadataImplementor的实例,必须实现SessionFactoryBuilderFactory并注册,以便ServiceLoader可以识别此服务:

SessionFactoryBuilderFactory的实现:

    public class MetadataProvider implements SessionFactoryBuilderFactory {

        private static MetadataImplementor metadata;

        @Override
        public SessionFactoryBuilder getSessionFactoryBuilder(MetadataImplementor metadata, SessionFactoryBuilderImplementor defaultBuilder) {
            this.metadata = metadata;
            return defaultBuilder; //Just return the one provided in the argument itself. All we care about is the metadata :)
        }

        public static MetadataImplementor getMetadata() {
            return metadata;
        }
    }

为了注册以上内容,请在以下路径中创建简单的文本文件(假设它是一个maven项目,最终我们需要在类路径中提供“ META-INF”文件夹):

src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactory

文本文件的内容应为一行(如果需要注册多个实例,甚至可以为多行),说明SessionFactoryBuilderFactory实现的完全限定的类路径。例如,对于上述类,如果您的程序包名称为“
com.yourcompany.prj”,则文件内容应为以下内容。

com.yourcompany.prj.MetadataProvider

就是这样,如果您运行应用程序,spring应用程序或独立的hibernate模式,则在启动hibernate模式后,将通过静态方法获得一个MetadataImplementor实例。

更新1:

无法通过Spring注入它。我研究了Hibernate的源代码,并且元数据对象没有存储在SessionFactory中的任何位置(这是我们从Spring获得的)。因此,不可能注入它。但是,如果您希望使用Spring的方式,则有两种选择:

  1. 扩展现有的类并从头开始进行自定义

LocalSessionFactoryBean-> MetadataSources-> MetadataBuilder

LocalSessionFactoryBean是您在Spring中配置的,并且具有MetadataSources对象。MetadataSources创建MetadataBuilder,后者又创建MetadataImplementor。以上所有操作均不存储任何内容,它们只是动态创建对象并返回。如果要使用MetaData实例,则应扩展和修改上述类,以便它们在返回之前存储相应对象的本地副本。这样,您可以引用MetadataImplementor。但是除非确实需要,否则我不会真正推荐这样做,因为API可能会随着时间而变化。

  1. 另一方面,如果您不介意从SessionFactory构造MetaDataImplemetor,则以下代码将为您提供帮助:
        EntityManagerFactoryImpl emf=(EntityManagerFactoryImpl)lcemfb.getNativeEntityManagerFactory();
    SessionFactoryImpl sf=emf.getSessionFactory();
    StandardServiceRegistry serviceRegistry = sf.getSessionFactoryOptions().getServiceRegistry();
    MetadataSources metadataSources = new MetadataSources(new BootstrapServiceRegistryBuilder().build());
    Metadata metadata = metadataSources.buildMetadata(serviceRegistry);
    SchemaUpdate update=new SchemaUpdate(serviceRegistry,metadata); //To create SchemaUpdate

    // You can either create SchemaExport from the above details, or you can get the existing one as follows:
    try {
        Field field = SessionFactoryImpl.class.getDeclaredField("schemaExport");
        field.setAccessible(true);
        SchemaExport schemaExport = (SchemaExport) field.get(serviceRegistry);
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
        e.printStackTrace();
    }


 类似资料:
  • 本文向大家介绍Spring4整合Hibernate5详细步骤,包括了Spring4整合Hibernate5详细步骤的使用技巧和注意事项,需要的朋友参考一下 Spring与Hiberante整合 通过hibernate的学习,我们知道,hibernate主要在hibernate.cfg.xml配置文件中 接下来我们看一下hibernate的一个配置文件 hibernate配置文件 hibernate

  • 我有一个Pojo对象,由Jersey使用jackson序列化: 序列化产生了一个像这样的Json: 但是,当我尝试像这样反序列化来自客户端的消息时: 我得到以下错误: 无法识别的字段“键”(类com.example.server.api.书摘),未标记为可忽略 我不知道问题是来自服务器生成的JSOn还是来自客户端的反序列化。 您知道问题是什么以及如何纠正吗? 非常谢谢。

  • 根据Spring网站上的这个教程,我知道了如何使用Stomp和Spring4建立一个基于WebSocket的应用程序。在客户端,我们有: 在服务器端,控制器中有以下内容: 现在,我明白了确保如果消息发送到目标,那么将调用方法。由于订阅了,将消息发送回。 那么,有什么方法可以用Spring4、SockJS和没有跺脚的情况下做到这一点呢?还是Spring4WebSocket只支持stomp?

  • 我无法让Log4j2在日志文件上写入Spring和Spring Security日志消息(后者我绝对需要解决一个问题)。我在这里和其他地方读了很多(当然,就像在Spring参考中),但我无法使我找到的解决方案适用于我的案例。 需要注意的是,在下面的两个解决方案中,地雷日志记录消息和hibernate消息都正确地写入了文件。该问题只影响Spring消息。 据我所知,Spring使用jcl(commo

  • 问题内容: 我正在尝试确定是否可以发布表格之外的其他数据。 这是我认为可行的方法,但仅发送而不发送表单数据。 有人有什么想法吗? 问题答案: 您可以使用 [docs]并添加其他数据:

  • 我需要帮助一个问题,我遇到了包装我的程序与JPackage。该程序是在Eclipse中创建的非模块化JavaFX应用程序。在Eclipse中,应用程序可以精确地编译和运行。但当我使用命令提示符进行编译和运行时,编译工作了,但应用程序不再运行了。我得到以下错误消息: javac--module-path%path_to_fx%--add-modules javafx.controls,javafx.