`
hanks_lin
  • 浏览: 5220 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Spring和Hibernate动态建表及动态加载映射文件(无需Session factory Rebuild)

阅读更多
Spring与Hibernate动态建表及动态加载映射文件(无需SessionFactory Rebuild)



J.Office2有一功能是工作流支持动态表单设计,设计后可以动态生成数据库表,并且支持实时查询(单表及多表均可)。



         由于J.Office2版本中采用了Hibernate作为底层的ORM框架,结合Spring框架,Spring容器启动后,SessionFactory就会被注入到各个业务的Dao层中去。



        动态建表功能比较容易实现,我们可以new一个SessionFactory,然后把它的配置属性hibernate.hbm2ddl.auto改为update或create,就可以达到动态修改表结构的效果。



            但若要加入新的hbm或class,需要重新调用SessionFactoryBean来获取一个全新的SessionFactory,这种方案试过了,效果并不理想。重新加载,会导致大量的hbm或class文件重新加载,实在有点慢。并且严重影响现在注入SessionFactory的Dao。若Dao采用动态构建SessionFactory,性能又是一问题。而Hibernate没有提供SessionFactory动态加入hbm或Class文件。所以实在无计可施。



      所以最终还是回到如何扩展Hibernate的SessionFactory类中去了,这想法已经有不少开发人员尝试过,JE也有一帖子专门讨论这个。不过仅是一Demo,不完善。我们提供了两个扩展的类(修改Hibernate中的两类,使其支持动态加入配置文件,并且能实时查询。



我们仅需要修改两个类,一个是Configuration,在其里面加一方法,如下:

     public void doComplie(){
         secondPassCompile();
     }



     修改



在SessonFactoryImpl类中加入以下方法,(有一些变量值不能修改的,请改为可修改)


Java代码  收藏代码

Java代码   收藏代码

    //add by csx 
    public void addNewConfig(Configuration cfg){ 
        log.info("add NewConfig....."); 
         
        Mapping mapping=this.configuration.getMapping(); 
        this.filters.putAll( cfg.getFilterDefinitions() ); 
        //Generators: 
        Iterator classes = cfg.getClassMappings(); 
        while ( classes.hasNext() ) { 
            PersistentClass model = (PersistentClass) classes.next(); 
             
            if ( !model.isInherited() ) { 
                IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator( 
                        settings.getDialect(), 
                        settings.getDefaultCatalogName(), 
                        settings.getDefaultSchemaName(), 
                        (RootClass) model 
                    ); 
                identifierGenerators.put( model.getEntityName(), generator ); 
            } 
        } 
     
        /////////////////////////////////////////////////////////////////////// 
        // Prepare persisters and link them up with their cache 
        // region/access-strategy 
     
        String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + "."; 
         
        Map entityAccessStrategies = new HashMap(); 
        Map tmpEntityPersisters=new HashMap(); 
        Map tmpClassMetadata=new HashMap(); 
         
         
        this.configuration.getClassMap().putAll(cfg.getClassMap()); 
        classes = cfg.getClassMappings(); 
     
        while ( classes.hasNext() ) { 
             
            PersistentClass model = (PersistentClass) classes.next(); 
             
            model.prepareTemporaryTables( mapping, settings.getDialect() ); 
            String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName(); 
             
            // cache region is defined by the root-class in the hierarchy... 
            EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName ); 
            if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) { 
                AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() ); 
                if ( accessType != null ) { 
                     
                    log.trace( "Building cache for entity data [" + model.getEntityName() + "]" ); 
                    EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) ); 
                    accessStrategy = entityRegion.buildAccessStrategy( accessType ); 
                    entityAccessStrategies.put( cacheRegionName, accessStrategy ); 
                    allCacheRegions.put( cacheRegionName, entityRegion ); 
                } 
            } 
            EntityPersister cp = PersisterFactory.createClassPersister( model, accessStrategy, this, cfg.getMapping() ); 
            tmpEntityPersisters.put( model.getEntityName(), cp ); 
            tmpClassMetadata.put( model.getEntityName(), cp.getClassMetadata() ); 
             
        } 
         
        //Named Queries: 
        namedQueries.putAll(cfg.getNamedQueries()); 
        namedSqlQueries.putAll( cfg.getNamedSQLQueries() ); 
        sqlResultSetMappings.putAll(cfg.getSqlResultSetMappings()); 
        imports.putAll(cfg.getImports()); 
     
        entityPersisters.putAll(tmpEntityPersisters); 
     
        classMetadata.putAll(tmpClassMetadata); 
         
        Map tmpEntityToCollectionRoleMap = new HashMap(); 
        Map tempCollectionPersisters=new HashMap(); 
         
        this.configuration.getCollectionMap().putAll(cfg.getCollectionMap()); 
        Iterator collections = cfg.getCollectionMappings(); 
     
        while ( collections.hasNext() ) { 
            Collection model = (Collection) collections.next(); 
            final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName(); 
            final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() ); 
            CollectionRegionAccessStrategy accessStrategy = null; 
            if ( accessType != null && settings.isSecondLevelCacheEnabled() ) { 
                log.trace( "Building cache for collection data [" + model.getRole() + "]" ); 
                CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) ); 
                accessStrategy = collectionRegion.buildAccessStrategy( accessType ); 
                entityAccessStrategies.put( cacheRegionName, accessStrategy ); 
                allCacheRegions.put( cacheRegionName, collectionRegion ); 
            } 
            CollectionPersister persister = PersisterFactory.createCollectionPersister(this.getConfiguration(), model, accessStrategy, this) ; 
            tempCollectionPersisters.put( model.getRole(), persister.getCollectionMetadata() ); 
            Type indexType = persister.getIndexType(); 
            if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) { 
                String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this ); 
                Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName ); 
                if ( roles == null ) { 
                    roles = new HashSet(); 
                    tmpEntityToCollectionRoleMap.put( entityName, roles ); 
                } 
                roles.add( persister.getRole() ); 
            } 
            Type elementType = persister.getElementType(); 
            if ( elementType.isAssociationType() && !elementType.isAnyType() ) { 
                String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this ); 
                Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName ); 
                if ( roles == null ) { 
                    roles = new HashSet(); 
                    tmpEntityToCollectionRoleMap.put( entityName, roles ); 
                } 
                roles.add( persister.getRole() ); 
            } 
             
        } 
        //加入新的 
        collectionPersisters.putAll(tempCollectionPersisters); 
     
        Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator(); 
        while ( itr.hasNext() ) { 
            final Map.Entry entry = ( Map.Entry ) itr.next(); 
            entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) ); 
        } 
         
        collectionRolesByEntityParticipant.putAll( tmpEntityToCollectionRoleMap); 
     
        // after *all* persisters and named queries are registered 
        Iterator iter = tmpEntityPersisters.values().iterator(); 
        while ( iter.hasNext() ) { 
            ( (EntityPersister) iter.next() ).postInstantiate(); 
        } 
        iter = tempCollectionPersisters.values().iterator(); 
        while ( iter.hasNext() ) { 
            ( (CollectionPersister) iter.next() ).postInstantiate(); 
        } 
         
        queryPlanCache=new QueryPlanCache(this); 
         
         
    } 



我们动态加入实体,动态可进行查询,Hibernate提供几种实体的查询策略,其中一个是我们常用的pojo,若采用该方法,我们得加上hbm与 class类或仅是含注解的class至hibernate的SessionFactory,这种方案并且没有问题,但会遇到当我们修改表单字段,重新生 成对应的实体时,我们就会遇到原有的实体class不能在ClassLoader里卸载。使用的还是旧的Class,达不到动态查询的效果。若使用动态的 ClassLoader,代码将变得很复杂。(尝试过,代码相对比较繁杂)



        还好Hibernate提供了另一种实体查询策略,基于Map的动态实体。基于这种方式,我们配置一个一对多的表,其示例代码如下:



MainEntity.hbm.xml
Java代码   收藏代码

    <?xml version="1.0"?> 
    <!DOCTYPE hibernate-mapping PUBLIC 
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
    <hibernate-mapping> 
        <class table="main_entity" entity-name="MainEntity"> 
            <id name="mainId" column="mainId" type="java.lang.Long"> 
                <generator class="native"/> 
            </id> 
            <property name="itemSubject" type="java.lang.String" length="128"/> 
            <property name="itemDescp" type="java.lang.String" /> 
            <property name="createtime" type="java.util.Date" /> 
            <bag name="subEntitys" 
                 table="sub_entity" 
                 lazy="false" 
                 inverse="true" 
                 cascade="save-update,delete-orphan" 
            > 
                <key> 
                    <column name="mainId"/> 
                </key> 
                <one-to-many entity-name="SubEntity"/> 
            </bag> 
        </class> 
    </hibernate-mapping> 

SubEntity.hbm.xml




Java代码   收藏代码

    <?xml version="1.0"?> 
    <!DOCTYPE hibernate-mapping PUBLIC 
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 
    <hibernate-mapping> 
        <class table="sub_entity" entity-name="SubEntity"> 
            <id name="subId" column="subId" type="java.lang.Long"> 
                <generator class="native"/> 
            </id> 
            <property name="subject" type="java.lang.String" length="128"/> 
            <property name="createtime" type="java.util.Date"/> 
            <many-to-one name="mainEntity" entity-name="MainEntity" not-null="false" fetch="select"> 
                <column name="mainId"></column> 
            </many-to-one> 
        </class> 
    </hibernate-mapping> 



为两实体插入数据后,可动态测试如下:




Java代码   收藏代码

    public static void main(String[]args){ 
            ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:app-context.xml"); 
     
            MyAnnotationSessionFactoryBean sessionFactoryBean=(MyAnnotationSessionFactoryBean)ctx.getBean("&sessionFactory"); 
             
            SessionFactoryImpl sessionFactoryImpl=(SessionFactoryImpl)sessionFactoryBean.getObject(); 
         
            Configuration cfg=new Configuration();   
            //cfg.configure(); 
             
            cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/MainEntity.hbm.xml"); 
            cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/SubEntity.hbm.xml"); 
            cfg.doComplie(); 
     
            sessionFactoryImpl.addNewConfig(cfg); 
     
            MainEntityDao dao=(MainEntityDao)ctx.getBean("mainEntityDao"); 
     
            List list=dao.query(); 
     
            for(int i=0;i<list.size();i++){ 
                Map map=(Map)list.get(i); 
                Iterator it=map.keySet().iterator(); 
                while(it.hasNext()){ 
                    //String key=(String)it.next(); 
                    Object key=it.next(); 
                    Object val=map.get(key); 
                    System.out.println("--------------->key:"+key ); 
                } 
            } 
     
            Configuration cfg2=new Configuration(); 
            cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/MainEntity2.hbm.xml"); 
            cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/SubEntity2.hbm.xml"); 
            cfg2.doComplie(); 
            sessionFactoryImpl.addNewConfig(cfg2); 
             
            List list2=dao.query(); 
             
            for(int i=0;i<list2.size();i++){ 
                Map map=(Map)list2.get(i); 
                Iterator it=map.keySet().iterator(); 
                while(it.hasNext()){ 
                    //String key=(String)it.next(); 
                    Object key=it.next(); 
                    Object val=map.get(key); 
                    System.out.println("key:"+key ); 
                } 
            } 
             
        } 


Java代码   收藏代码

    MainEntity2.hbm.xml与SubEntity2.hbm.xml文件相对原来的文件增加了一些列或删除了一些列 



执行后,可以实时看到不同的结果,并且不会影响现有的dao。
分享到:
评论

相关推荐

    J2EE利用Hibernate采用B/S架构网页设计

    * Rebuild hibernate session factory * */ public static void rebuildSessionFactory() { try { configuration.configure(configFile); sessionFactory = configuration.buildSessionFactory(); } catch ...

    Visual Studio 未能加载文件或程序集解决方案

    在开发过程中,遇到“Visual Studio 未能加载文件或程序集解决方案”的问题,通常是由于多种原因导致的。这可能涉及到依赖项丢失、配置错误、权限问题或者是项目引用的问题。以下是一些详细的解决步骤和可能的原因...

    前端开源库-workers-factory-rebuild

    "Workers-Factory Rebuild" 是一款专门针对这一需求设计的前端开源库,它旨在通过智能地利用 Web Workers 技术,提升前端应用程序的性能和响应速度。本文将深入探讨该库的核心理念、工作原理及其在实际项目中的应用...

    REBUILD 通过创新的业务流程引擎帮助你快速搭建各类企业管理系统,全图形化配置无需了解技术

    REBUILD 通过创新的业务流程引擎帮助你快速搭建各类企业管理系统,全图形化配置无需了解技术。REBUILD 侧重于业务需求实现,而非基础技术框架或项目启动模板,通过 REBUILD 可以真正实现零代码快速搭建!无需编程、...

    VB6.0源码示例文件之 动态增添和移除菜单

    本示例文件提供了关于如何在运行时动态管理菜单栏的方法,这对于初学者了解和掌握VB6.0的菜单控件使用具有重要的学习价值。 首先,我们需要了解VB6.0中的菜单系统。在VB6.0中,菜单通常通过MenuStrip控件来创建和...

    SQL置疑REPAIR_REBUILD修复

    SQL Server 修复工具 REPAIR_REBUILD SQL Server 是一个复杂的关系数据库管理系统,它提供了强大的数据存储和管理功能。但是,当 SQL Server 遇到 I/O 错误、磁盘问题或其他错误时,数据库可能会损坏,导致数据丢失...

    IntelliJ IDEA修改了mybatis mapper xml后不用重启tomcat,自动热发布 热更新 热部署.zip

    总的来说,通过合理配置IDEA的自动构建选项,以及Mybatis Plus的热加载设置,我们可以实现在修改Mapper XML文件后,无需重启Tomcat即可看到更新效果,大大提高开发效率。如果遇到XML文件未被自动检测到更新的情况,...

    Android studio加载本地html的文档问题

    ### Android Studio加载本地HTML文件详解 #### 一、引言 在进行Android应用开发时,有时需要在应用内部展示HTML内容。例如,显示帮助文档、用户手册或是简单的网页信息等。传统的Eclipse环境下,通常的做法是将...

    WZ-Explorer-Rebuild-master_Explorer_tool_

    这些文件通常以二进制格式存储,直接查看难以理解,而WZ-Explorer-Rebuild-master就是用来解析和编辑这类文件的利器。它允许用户浏览、搜索、修改WZ文件内容,从而深入探究游戏的内在机制。 该工具的核心功能包括:...

    DELL_服务器硬盘掉线后的REBUILD修复操作全过程

    ### DELL服务器硬盘掉线后的REBUILD修复操作详解 在企业级服务器运维中,RAID技术作为数据冗余和性能提升的重要手段,被广泛应用。然而,在长时间运行或遇到突发状况时,服务器硬盘可能会出现故障,导致RAID阵列...

    Android studio的make Project、clean Project、Rebuild Project

    Sync Project with gradle files:对gradle...Rebuild Project :包含了Clean的操作,并对整个项目进行了重新编译(包括NDK和资源文件),因此耗时相对较长; Invalidate Cache/Restart AndroidStudio:自动生成的项目

    rebuild_db-1.0-rc1.zip

    标题“rebuild_db-1.0-rc1.zip”表明这是一个软件或工具的打包文件,版本为1.0的候选发布版1(RC1)。在IT行业中,RC1通常代表Release Candidate 1,这意味着该软件已经接近最终版本,但在正式发布前还需要进行最后...

    qt生成so文件,再调用so文件-1.pdf

    "Qt 生成 so 文件并调用 so 文件" Qt 是一个跨平台的应用程序开发框架,它支持多种操作系统,包括 Windows、Linux 和 macOS。在 Linux 系统中,因为不支持 dll 文件,而是支持 so 文件,因此,需要生成 so 文件...

    创建Spring boot的三种方式

    Spring Boot 项目创建方法 Spring Boot 是一个基于 Java 的开源框架,旨在简化...创建 Spring Boot 项目有多种方式,但无论选择哪种方式,都是为了快速生成一个基本的 Spring Boot 项目,供开发者进一步开发和完善。

    Solar Board Rebuild on TI part4

    Solar Board Rebuild on TI part4

    W589_Rebuild_Tool.exe

    W589_Rebuild_Tool.exe

    Android利用.c文件生成So库

    这种情况下,我们可以将C或C++代码编译为动态链接库(.so文件),然后在Android应用中通过JNI(Java Native Interface)进行调用。下面我们将详细介绍如何在Android Studio中创建并使用C文件生成So库,以及如何在...

    热部署配置包、使用文档

    此外,还可以使用插件如JRebel,它提供了更强大的热部署能力,包括对Spring、Hibernate等框架的支持,可以在不重启应用的情况下更新资源文件、配置文件甚至部分数据库结构。 Eclipse也有类似的功能,例如“Build ...

    arx.rar_ A_ arx.rar_ARx_ObjectARX_rebuild

    开发平台VC6.0及ObjectARX3.0(本程序所涉及的文件已包含在安装程序中)。 1. 解压缩source.zip到C盘,自动生成c:\source目录。 2.在VC6下打开工程c:\source\MyModelessSheet.dsw。 3.编译生成c:/source/debug/...

    Unity UI 重建(Rebuild)分析

    通过编写 MonoBehaviour 收集Unity UI 中的当前帧有那些元素触发了Rebuild。方便进行UI重建方面的性能检查,以便提升性能。 原理就是通过对 CanvasUpdateRegistry 中的属性值型判断收集实现。由于UGUI中...

Global site tag (gtag.js) - Google Analytics