当前位置:  开发笔记 > 编程语言 > 正文

使用Hibernate 5和Spring 4的编程SchemaExport/SchemaUpdate

如何解决《使用Hibernate5和Spring4的编程SchemaExport/SchemaUpdate》经验,为你挑选了2个好方法。

使用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,我必须使用一些MetadataImplementor,这些对象中似乎没有.我还试图用MetadataSourcesserviceRegistry.但它确实说这是错误的ServiceRegistry.

有没有其他方法让这个工作?



1> valery.barys..:

这个问题的基本思路是:

其实施org.hibernate.integrator.spi.Integrator将所需数据存储到某个持有者.将实施注册为服务,并在您需要的地方使用它.

你可以在这里找到的工作示例https://github.com/valery-barysok/spring4-hibernate5-stackoverflow-34612019


创造org.hibernate.integrator.api.integrator.Integrator阶级

import hello.HibernateInfoHolder;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;

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

    @Override
    public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        HibernateInfoHolder.setMetadata(metadata);
        HibernateInfoHolder.setSessionFactory(sessionFactory);
        HibernateInfoHolder.setServiceRegistry(serviceRegistry);
    }

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

创建META-INF/services/org.hibernate.integrator.spi.Integrator文件

org.hibernate.integrator.api.integrator.Integrator

import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        new SchemaExport((MetadataImplementor) HibernateInfoHolder.getMetadata()).create(true, true);
        new SchemaUpdate(HibernateInfoHolder.getServiceRegistry(), (MetadataImplementor) HibernateInfoHolder.getMetadata()).execute(true, true);
    }
}



2> James..:

我想补充一下Aviad的答案,根据OP的要求完成它.

内部:

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

    服务加载

    调用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

就是这样,如果您运行应用程序,弹簧应用程序或独立休眠,一旦hibernate被引导,您将通过静态方法获得MetadataImplementor的实例.

更新1:

它无法通过Spring注入.我深入研究了Hibernate的源代码,并且元数据对象没有存储在SessionFactory中的任何地方(这是我们从Spring获得的).所以,它不可能注入它.但是如果你想以Spring的方式使用它,有两种选择:

    扩展现有类并从中进行自定义

LocalSessionFactoryBean - > MetadataSources - > MetadataBuilder

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

    另一方面,如果您不介意从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();
    }
    

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有