基本上我们有一个spring启动应用程序,它要求用户可以定义他/她自己的字段集,并且这些字段应该在运行时通过JPA / Hibernate保存在他们自己的类/表中。这些类将通过bytebuddy动态生成。
所有这些都应该动态完成而无需重新启动应用程序。 Hibernate动态映射不是一个选项,因为我们将完全创建新类并重新映射它们。
我还考虑了EAV模型,但由于我们需要为每组数据使用单独的表,因此无法使用,因此JSON不能在同一个表中混合使用。
我考虑的第一个解决方案是代理EntityManagetFactory,当我们有一个新的实体进行映射时,我将重新创建EntityManagetFactory并将新的映射实体添加到其中,I&#39 ; ll还将hbm2ddl.auto设置为"更新"为了确保创建新的表格方案。
问题是我不知道其他可能需要代理的类,我相信我必须代理Hibernate SessionFactory,但我不确定还需要多少其他类。被重新创建和代理,我相信这是一条复杂的道路。
另一种解决方案是使用Hibernate OGM在SQL和NoSQL解决方案之间进行混合,但在这种情况下,我将松散与现有SQL实体之间的任何关系,而且我不赞成运行第二个NoSQL DB。
我还可以探索其他任何解决方案吗?
编辑:
我会使用bytebuddy来动态生成新类,并且它们会有@Entity注释,生成的类被写入临时jar文件(例如/tmp/myjar.jar)
使用BeanPostProcessor.postProcessAfterInitialization我将使用代理类替换LocalContainerEntityManagerFactoryBean。
我还使用LocalContainerEntityManagerFactoryBean .setPersistenceUnitPostProcessors添加一个额外的处理器来处理新创建的jar中的类
所以现在用bytebuddy创建新类之后,我会手动调用LocalContainerEntityManagerFactoryBeanProxy.afterProperties来完成引导JPA和hibernate层的所有工作,我也设置了" hibernate.hbm2ddl.auto"财产到"更新"这样就可以创建模式(我知道在生产环境中这样做很危险)
答案 0 :(得分:0)
Hibernate将实体映射到表,并在引导期间构建元数据。因此,在应用程序运行时,您无法动态修改它。
但是,只要您在不修改现有结构的情况下继续添加新表,就可以在架构级别解决此问题:
或者,只使用像MongoDB这样的NoSQL数据库和Hibernate OGM,因为无论如何你的要求都不适合关系数据库。
但是,如果您已经使用了RDBMS,那么it's simpler to just use JSON而不是仅仅因为这个原因而切换到NoSQL数据库。
答案 1 :(得分:0)
首先,问题是如何在热部署中添加实体类。我们可以通过一些交换工具(spring-boot-devtools或maven copy resource)来实现。 其次,要构建不同的实体模型,可以使用JPA继承(https://en.wikibooks.org/wiki/Java_Persistence/Inheritance) 或者jpa rowmapper。
但是,我认为将Json对象持久化为数据库中的文本更为轻松,并使服务的使用者(前端或其他服务)解析它。
另一种方法是尝试通过类路径在运行时加载类。我将尝试持久化Json对象作为文本及其在ddbb中的类型。然后在application.properties中创建其类型和类路径的映射(数据的类java),然后执行以下操作:
static{
Map<String, String> typeClassPathMap = ......// from properties
File file = new File("c:\\class-path\\");
// Convert File to a URL
URL url = file.toURL();
// file:/c:/myclasses/
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
}
Class<?> loadClass(String type){
Class clazz = urlClassLoader.loadClass(typeClassPathMap.get(type));
}
它将在运行时读取类,并可通过属性进行配置。之后,对于每种类型的数据,我们在属性文件中定义su类型和类路径。当数据来自ddbb时,我们使用它的类型来获取java类,并将其解析为object。当我们需要创建新类型的数据时,我们将类留在类路径中,并在属性中进行配置。