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

Spring与Hibernate动态建表及动态加载映射文件(无需SessionFactory 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代码   收藏代码
  1. //add by csx  
  2. public void addNewConfig(Configuration cfg){  
  3.     log.info("add NewConfig.....");  
  4.       
  5.     Mapping mapping=this.configuration.getMapping();  
  6.     this.filters.putAll( cfg.getFilterDefinitions() );  
  7.     //Generators:  
  8.     Iterator classes = cfg.getClassMappings();  
  9.     while ( classes.hasNext() ) {  
  10.         PersistentClass model = (PersistentClass) classes.next();  
  11.           
  12.         if ( !model.isInherited() ) {  
  13.             IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(  
  14.                     settings.getDialect(),  
  15.                     settings.getDefaultCatalogName(),  
  16.                     settings.getDefaultSchemaName(),  
  17.                     (RootClass) model  
  18.                 );  
  19.             identifierGenerators.put( model.getEntityName(), generator );  
  20.         }  
  21.     }  
  22.   
  23.     ///  
  24.     // Prepare persisters and link them up with their cache  
  25.     // region/access-strategy  
  26.   
  27.     String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";  
  28.       
  29.     Map entityAccessStrategies = new HashMap();  
  30.     Map tmpEntityPersisters=new HashMap();  
  31.     Map tmpClassMetadata=new HashMap();  
  32.       
  33.       
  34.     this.configuration.getClassMap().putAll(cfg.getClassMap());  
  35.     classes = cfg.getClassMappings();  
  36.   
  37.     while ( classes.hasNext() ) {  
  38.           
  39.         PersistentClass model = (PersistentClass) classes.next();  
  40.           
  41.         model.prepareTemporaryTables( mapping, settings.getDialect() );  
  42.         String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName();  
  43.           
  44.         // cache region is defined by the root-class in the hierarchy...  
  45.         EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName );  
  46.         if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) {  
  47.             AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );  
  48.             if ( accessType != null ) {  
  49.                   
  50.                 log.trace( "Building cache for entity data [" + model.getEntityName() + "]" );  
  51.                 EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );  
  52.                 accessStrategy = entityRegion.buildAccessStrategy( accessType );  
  53.                 entityAccessStrategies.put( cacheRegionName, accessStrategy );  
  54.                 allCacheRegions.put( cacheRegionName, entityRegion );  
  55.             }  
  56.         }  
  57.         EntityPersister cp = PersisterFactory.createClassPersister( model, accessStrategy, this, cfg.getMapping() );  
  58.         tmpEntityPersisters.put( model.getEntityName(), cp );  
  59.         tmpClassMetadata.put( model.getEntityName(), cp.getClassMetadata() );  
  60.           
  61.     }  
  62.       
  63.     //Named Queries:  
  64.     namedQueries.putAll(cfg.getNamedQueries());  
  65.     namedSqlQueries.putAll( cfg.getNamedSQLQueries() );  
  66.     sqlResultSetMappings.putAll(cfg.getSqlResultSetMappings());  
  67.     imports.putAll(cfg.getImports());  
  68.   
  69.     entityPersisters.putAll(tmpEntityPersisters);  
  70.   
  71.     classMetadata.putAll(tmpClassMetadata);  
  72.       
  73.     Map tmpEntityToCollectionRoleMap = new HashMap();  
  74.     Map tempCollectionPersisters=new HashMap();  
  75.       
  76.     this.configuration.getCollectionMap().putAll(cfg.getCollectionMap());  
  77.     Iterator collections = cfg.getCollectionMappings();  
  78.   
  79.     while ( collections.hasNext() ) {  
  80.         Collection model = (Collection) collections.next();  
  81.         final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();  
  82.         final AccessType accessType = AccessType.parse( model.getCacheConcurrencyStrategy() );  
  83.         CollectionRegionAccessStrategy accessStrategy = null;  
  84.         if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {  
  85.             log.trace( "Building cache for collection data [" + model.getRole() + "]" );  
  86.             CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );  
  87.             accessStrategy = collectionRegion.buildAccessStrategy( accessType );  
  88.             entityAccessStrategies.put( cacheRegionName, accessStrategy );  
  89.             allCacheRegions.put( cacheRegionName, collectionRegion );  
  90.         }  
  91.         CollectionPersister persister = PersisterFactory.createCollectionPersister(this.getConfiguration(), model, accessStrategy, this) ;  
  92.         tempCollectionPersisters.put( model.getRole(), persister.getCollectionMetadata() );  
  93.         Type indexType = persister.getIndexType();  
  94.         if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {  
  95.             String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );  
  96.             Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );  
  97.             if ( roles == null ) {  
  98.                 roles = new HashSet();  
  99.                 tmpEntityToCollectionRoleMap.put( entityName, roles );  
  100.             }  
  101.             roles.add( persister.getRole() );  
  102.         }  
  103.         Type elementType = persister.getElementType();  
  104.         if ( elementType.isAssociationType() && !elementType.isAnyType() ) {  
  105.             String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this );  
  106.             Set roles = ( Set ) tmpEntityToCollectionRoleMap.get( entityName );  
  107.             if ( roles == null ) {  
  108.                 roles = new HashSet();  
  109.                 tmpEntityToCollectionRoleMap.put( entityName, roles );  
  110.             }  
  111.             roles.add( persister.getRole() );  
  112.         }  
  113.           
  114.     }  
  115.     //加入新的  
  116.     collectionPersisters.putAll(tempCollectionPersisters);  
  117.   
  118.     Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();  
  119.     while ( itr.hasNext() ) {  
  120.         final Map.Entry entry = ( Map.Entry ) itr.next();  
  121.         entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );  
  122.     }  
  123.       
  124.     collectionRolesByEntityParticipant.putAll( tmpEntityToCollectionRoleMap);  
  125.   
  126.     // after *all* persisters and named queries are registered  
  127.     Iterator iter = tmpEntityPersisters.values().iterator();  
  128.     while ( iter.hasNext() ) {  
  129.         ( (EntityPersister) iter.next() ).postInstantiate();  
  130.     }  
  131.     iter = tempCollectionPersisters.values().iterator();  
  132.     while ( iter.hasNext() ) {  
  133.         ( (CollectionPersister) iter.next() ).postInstantiate();  
  134.     }  
  135.       
  136.     queryPlanCache=new QueryPlanCache(this);  
  137.       
  138.       
  139. }  
 

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

 

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

 

MainEntity.hbm.xml

Java代码   收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC  
  3.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class table="main_entity" entity-name="MainEntity">  
  7.         <id name="mainId" column="mainId" type="java.lang.Long">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="itemSubject" type="java.lang.String" length="128"/>  
  11.         <property name="itemDescp" type="java.lang.String" />  
  12.         <property name="createtime" type="java.util.Date" />  
  13.         <bag name="subEntitys"  
  14.              table="sub_entity"  
  15.              lazy="false"  
  16.              inverse="true"  
  17.              cascade="save-update,delete-orphan"  
  18.         >  
  19.             <key>  
  20.                 <column name="mainId"/>  
  21.             </key>  
  22.             <one-to-many entity-name="SubEntity"/>  
  23.         </bag>  
  24.     </class>  
  25. </hibernate-mapping>  

 SubEntity.hbm.xml

 

 

Java代码   收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC  
  3.         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class table="sub_entity" entity-name="SubEntity">  
  7.         <id name="subId" column="subId" type="java.lang.Long">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="subject" type="java.lang.String" length="128"/>  
  11.         <property name="createtime" type="java.util.Date"/>  
  12.         <many-to-one name="mainEntity" entity-name="MainEntity" not-null="false" fetch="select">  
  13.             <column name="mainId"></column>  
  14.         </many-to-one>  
  15.     </class>  
  16. </hibernate-mapping>  
 

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

 

 

Java代码   收藏代码
  1. public static void main(String[]args){  
  2.         ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:app-context.xml");  
  3.   
  4.         MyAnnotationSessionFactoryBean sessionFactoryBean=(MyAnnotationSessionFactoryBean)ctx.getBean("&sessionFactory");  
  5.           
  6.         SessionFactoryImpl sessionFactoryImpl=(SessionFactoryImpl)sessionFactoryBean.getObject();  
  7.       
  8.         Configuration cfg=new Configuration();    
  9.         //cfg.configure();  
  10.           
  11.         cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/MainEntity.hbm.xml");  
  12.         cfg.addFile("D:/download/eclipse/workspace2/SpringHibernate/src/com/hotent/entity/SubEntity.hbm.xml");  
  13.         cfg.doComplie();  
  14.   
  15.         sessionFactoryImpl.addNewConfig(cfg);  
  16.   
  17.         MainEntityDao dao=(MainEntityDao)ctx.getBean("mainEntityDao");  
  18.   
  19.         List list=dao.query();  
  20.   
  21.         for(int i=0;i<list.size();i++){  
  22.             Map map=(Map)list.get(i);  
  23.             Iterator it=map.keySet().iterator();  
  24.             while(it.hasNext()){  
  25.                 //String key=(String)it.next();  
  26.                 Object key=it.next();  
  27.                 Object val=map.get(key);  
  28.                 System.out.println("--------------->key:"+key );  
  29.             }  
  30.         }  
  31.   
  32.         Configuration cfg2=new Configuration();  
  33.         cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/MainEntity2.hbm.xml");  
  34.         cfg2.addFile("D:/dev/product/SpringHibernate/src/com/hotent/entity/SubEntity2.hbm.xml");  
  35.         cfg2.doComplie();  
  36.         sessionFactoryImpl.addNewConfig(cfg2);  
  37.           
  38.         List list2=dao.query();  
  39.           
  40.         for(int i=0;i<list2.size();i++){  
  41.             Map map=(Map)list2.get(i);  
  42.             Iterator it=map.keySet().iterator();  
  43.             while(it.hasNext()){  
  44.                 //String key=(String)it.next();  
  45.                 Object key=it.next();  
  46.                 Object val=map.get(key);  
  47.                 System.out.println("key:"+key );  
  48.             }  
  49.         }  
  50.           
  51.     }  
 
Java代码   收藏代码
  1. MainEntity2.hbm.xml与SubEntity2.hbm.xml文件相对原来的文件增加了一些列或删除了一些列  

 

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


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值