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

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类中加入以下方法,(有一些变量值不能修改的,请改为可修改)

 

	//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

<?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

 

 

<?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>

 

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

 

 

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 );
			}
		}
		
	}

 

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

 

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

更多资讯请加QQ了解3102760881

 

 

分享到:
评论
13 楼 man1900 2011-08-05  
不修改该类,就不有办法修改hibernate原有的SessionFactory的实现,继承与改写是两个概念,是有区别并且有一些不能替代的。
12 楼 semmy 2011-07-29  
为什么 要改写Configuration类,Configuration类是可以继承的。
11 楼 semmy 2011-07-29  
semmy 写道
secondPassCompile();
这个方法在哪里,是干嘛用的?

sorry,我错了,没认真看清Hibernate源码。
10 楼 semmy 2011-07-29  
secondPassCompile();
这个方法在哪里,是干嘛用的?
9 楼 semmy 2011-07-29  
楼主是直接修改Hibernate的Configuration类和SessionFactoryImpl类吗?
8 楼 中国鱼tt 2011-05-18  
还有,SessionFactoryImpl.java类里添加的那个方法里用到了一个this.configuration变量,这个变量也没找到....
7 楼 中国鱼tt 2011-05-18  
ADD by csx for dynamic register hbm or class file to hiberate configuration
man1900 写道
//ADD by csx for dynamic register hbm or class file to hiberate configuration

public Mapping getMapping()  { 
         return this.mapping; 
}

public Map getClassMap(){
return this.classes;
}

public Map getCollectionMap(){
return this.collections;
}

public void doComplie(){
secondPassCompile();
}



这些是你加的代码呢,还是你从hibernate里面拷贝出来的呢?除了最后一个方法
6 楼 man1900 2011-05-13  
//ADD by csx for dynamic register hbm or class file to hiberate configuration

public Mapping getMapping()  { 
         return this.mapping; 
}

public Map getClassMap(){
return this.classes;
}

public Map getCollectionMap(){
return this.collections;
}

public void doComplie(){
secondPassCompile();
}
5 楼 中国鱼tt 2011-05-13  
我改的是hibernate3.3.0的
4 楼 中国鱼tt 2011-05-13  
楼主,我想请问一下,你所改的hibernate源码是什么版本的?我拷贝了你的代码到相应的类里面会有错误,比如this.configuration这个变量是不存在的,getMapping()方法在Configuration类里也是没有的....
3 楼 中国鱼tt 2011-05-13  
我是我发表的评论都不提交呢
2 楼 man1900 2011-02-02  
由于不需要重新加载,只是把需要你加的配置文件加入,影响很小
1 楼 haitaohehe 2011-01-29  
请教下楼主,如果扩展之后对性能的影响比例占多大呢?

相关推荐

    Spring与Hibernate集成

    **Spring与Hibernate集成详解** 在Java企业级应用开发中,Spring和Hibernate是两个非常重要的框架。Spring是一个全方位的轻量级应用框架,提供了强大的依赖注入、AOP(面向切面编程)以及各种服务管理功能。而...

    Spring+Hibernate 自动映射

    在实际应用中,Spring与Hibernate的集成通常涉及以下步骤: 1. **配置Hibernate**:设置Hibernate的配置文件(hibernate.cfg.xml),包括数据库连接信息、实体类扫描路径等。 2. **配置SessionFactory**:Spring会...

    Spring与Hibernate整合

    在"25_黑马程序员_黎活明_Spring2.5视频教程_搭建和配置Spring与Hibernate整合的环境.avi"这个文件中,可能详细演示了如何配置这些库到项目的类路径中。 接着,需要配置Spring的IoC容器。这可以通过XML配置文件完成...

    spring与hibernate的整合

    总结来说,Spring 与 Hibernate 的整合主要涉及 SessionFactory 的配置、DAO 类的实现以及事务管理。通过 Spring 的 IoC 容器管理数据访问资源,可以使应用更加解耦,同时利用 Spring 的事务管理功能,可以简化事务...

    spring 与hibernate的集成

    在进行Spring与Hibernate的集成时,首先要在`web.xml`中配置Spring的相关内容。这里有两个关键的元素:`context-param`和`listener`。`context-param`用于指定Spring应用上下文配置文件的位置,通常设置为`/WEB-INF/...

    spring-hibernate3.jar.zip

    《Spring与Hibernate集成详解》 在Java开发领域,Spring框架和Hibernate ORM工具是两个非常重要的组件,它们分别处理了应用程序的依赖注入(DI)和对象关系映射(ORM)。Spring作为一个全面的轻量级框架,提供了...

    spring+hibernate整合demo

    在"标签"中,"spring 整合 hibernate helloworld"进一步强调了这是关于Spring与Hibernate整合的基础教学,可能包含了一个简单的入门级示例。"helloworld"通常表示最基础的程序,用于展示框架的基本用法。 在"压缩...

    现有Mysql数据库,写Spring + Hibernate的配置文件

    Spring作为一个全面的开发框架,提供了依赖注入、AOP(面向切面编程)、事务管理等核心功能,而Hibernate则是一个优秀的对象关系映射(ORM)框架,使得Java开发者可以更加方便地操作数据库。在本案例中,我们将探讨...

    Spring+hibernate整合源代码

    Hibernate 则是一个强大的对象关系映射(ORM)框架,它简化了数据库操作,将 Java 对象与数据库表进行映射,使得开发者可以使用对象而不是 SQL 来操作数据库。 Spring 和 Hibernate 的整合主要涉及到以下几个方面:...

    spring和hibernate框架

    3. 整合 Spring 和 Hibernate:在 Spring 配置文件中声明 Hibernate 的 SessionFactory Bean,并使用 Spring 的事务管理器来控制事务。 4. 实体类和数据库表映射:使用 Hibernate 的注解或 XML 映射文件,将 Java 类...

    gwt+spring+hibernate

    Spring与GWT结合,可以在服务器端处理业务逻辑,通过GWT的Remote Procedure Call (RPC)机制与客户端进行通信。 3. **Hibernate ORM**: Hibernate 是一个流行的Java ORM(对象关系映射)框架,它允许开发者用Java...

    Struts2,Spring,Hibernate jar包下载

    此外,Spring还提供了与其他框架的整合包,如Spring与Hibernate的整合,使得事务管理、数据访问变得更加便捷。 **Hibernate** 是一个强大的对象关系映射(Object-Relational Mapping,ORM)框架,它将数据库操作...

    struts2+spring+hibernate 整合的jar包

    6. **整合Hibernate和Spring**:使用Spring的Hibernate支持,配置SessionFactory,可以通过`&lt;bean&gt;`标签创建SessionFactory并注入到需要的地方。 7. **测试**:编写单元测试和集成测试,验证SSH整合是否成功,确保...

    spring与hibernate以及ibatis集成的实例和具体配置图解

    3. 配置Hibernate:创建Hibernate的实体类,编写对应的映射文件,设置SessionFactory的配置。 4. 配置Ibatis:编写Mapper接口和XML映射文件,设置SqlSessionFactory的配置。 5. 在Spring中管理DAO:创建DAO接口,...

    Struts2,Spring与Hibernate整合应用,学生成绩管理系统

    ### Struts2、Spring与Hibernate整合应用:学生成绩管理系统 #### 一、知识点概览 本项目聚焦于Struts2、Spring与Hibernate三大框架的整合应用,旨在构建一个高效、稳定、易于维护的学生成绩管理系统。通过整合这...

    Spring与hibernate 整合 简单示例

    总结来说,Spring与Hibernate的整合使得Java开发人员能够更方便地管理数据库操作,并利用Spring的强大功能进行事务管理和组件装配。通过这个简单的示例,我们可以了解到如何配置Spring的环境,定义实体类,创建DAO和...

    非注解Springmvc+spring+hibernate 入门实例

    为了整合SpringMVC、Spring和Hibernate,你需要在Spring的配置文件中引入Hibernate的相关配置,如数据源、SessionFactory以及事务管理器。同时,你还需要配置一个Hibernate的本地SessionFactory Bean,以便Spring...

    spring mvc + spring + hibernate 全注解整合开发视频教程 12

    在Spring和Hibernate的整合中,Spring可以作为Hibernate的容器,管理SessionFactory和Transaction,这样我们就能够在Spring的管理下进行数据库操作。通过@PersistenceContext注解,Spring可以注入EntityManager,@...

    Spring与Hibernate整合小例子

    "Spring与Hibernate整合"是为了实现业务逻辑层和数据访问层的高效协作。整合过程通常包括以下几个步骤: 1. **引入依赖**:首先,需要在项目中添加Spring和Hibernate的相关库。这通常通过Maven或Gradle的依赖管理来...

    Spring与Hibernate集成---声明式事务

    本文将深入探讨如何将Spring与Hibernate进行集成,并重点介绍声明式事务的配置与使用。 Spring框架是一个全面的企业级应用开发框架,它提供依赖注入(DI)和面向切面编程(AOP)等功能,简化了Java应用的复杂性。另...

Global site tag (gtag.js) - Google Analytics