当前位置: 首页 > news >正文

hibernate动态创建表, 动态加载映射

为什么80%的码农都做不了架构师?>>>   hot3.png

参考:

1. http://www.iteye.com/topic/1112024    (Hibernate的动态模型)

2. http://man1900.iteye.com/blog/897933  (

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

)(注: 不知道是什么版本的hibernate, 反正4不能用)

如果大家有更好的实现方式, 希望能指点.谢谢

正文:

项目中有个需求, 要动态添加表结构, 同时要对其进行增删改查等操作, 而且还会有级联关系.



很多系统中都有这样的需求, 大部分都是使用JDBC自己实现. 最初也想这么做, 但是发现工作量不是一点的. 后来研究了一下hibernate发现如果对hibernate做一些扩展, 还是可以实现的.


涉及的内容:


1. Hibernate的动态模型

原理:

hibernate首先会通过Configuration读取配置文件, 然后进行解析, 最后生成SessionFactory, 当我们操作数据库时通过SessionFactory生成一个Session, 然后再进行对应的操作. 而要实现动态添加表(使用动态模型), 就需要解析XML, 然后将解析出来的内容整合到Session中, 保证在进行增删改查的时候能在Session中取到想要的东西. 因此要实现动态模型就有两个步骤.

1. 解析XML

2. 整合

解析的话, 直接使用

Configuration cfg = new Configuration();
 cfg.addFile(new File("Code.hbm.xml"));
 cfg.buildMappings();

就可以解析出来了. 

但是整合就麻烦了, 因为没有入口, hibernate没有提供现成的接口, 要不然也不会有这篇文章了. 通过查看SessionFactoryImpl源码可以发现, 所有解析configuration都是在构造函数中实现的, 那么, 我可完全可以复制一份构造函数, 然后做一定的改造, 使该方法可以合并Configuration内的东西, 当然可能会遗漏很多东西, 但是我们需求也不多.


在自己工程里创建包org.hibernate.internal, 把hibernate中的SessionFactoryImpl复制到这个包下, 然后对它进行修改, 之所以这样, 是为了让JDK在加载CLASS时替换掉hibernate自带的SessionFatoryImpl, 有些内容没法实现, 如Collections.unmodifiableMap处理过的MAP

代码在最下面, 添加这个方法后, 还要把构造函数里面几处Collections.unmodifiableMap去掉...


DEMO的话大家自己用hibernate里面的DEMO改一下就OK了

注:本方法基于hibernate-core4.2.0.Final

/**
     * 合并配置
     * @param cfg
     * @throws org.hibernate.HibernateException
     */
//    @SuppressWarnings( {"unchecked", "ThrowableResultOfMethodCallIgnored"})
    public void mergeConfiguration(final Configuration cfg) throws HibernateException {
        LOG.debug( "Building session factory" );

        Mapping mapping = cfg.buildMapping();

        this.properties.putAll( cfg.getProperties() );
        this.filters.putAll( cfg.getFilterDefinitions() );

        final RegionFactory regionFactory = cacheAccess.getRegionFactory();

        LOG.debugf( "Session factory constructed with filter configurations : %s", filters );
        LOG.debugf( "Instantiating session factory with properties: %s", properties );

        //Generators:

        Iterator classes = cfg.getClassMappings();
        while ( classes.hasNext() ) {
            PersistentClass model = (PersistentClass) classes.next();
            if ( !model.isInherited() ) {
                IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator(
                        cfg.getIdentifierGeneratorFactory(),
                        getDialect(),
                        settings.getDefaultCatalogName(),
                        settings.getDefaultSchemaName(),
                        (RootClass) model
                );
                identifierGenerators.put( model.getEntityName(), generator );
            }
        }


        ///
        // Prepare persisters and link them up with their cache
        // region/access-strategy

        final String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + ".";

        final PersisterFactory persisterFactory = serviceRegistry.getService( PersisterFactory.class );

        Map entityAccessStrategies = new HashMap();
        Map<String,ClassMetadata> classMeta = new HashMap<String,ClassMetadata>();
        classes = cfg.getClassMappings();
        while ( classes.hasNext() ) {
            final PersistentClass model = (PersistentClass) classes.next();
            model.prepareTemporaryTables( mapping, getDialect() );
            final 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() ) {
                final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
                if ( accessType != null ) {
                    LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() );
//                    EntityRegion entityRegion = regionFactory.buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) );
                    EntityRegion entityRegion = regionFactory.buildEntityRegion(cacheRegionName, properties, CacheDataDescriptionImpl.decode(model));

                    accessStrategy = entityRegion.buildAccessStrategy( accessType );
                    entityAccessStrategies.put( cacheRegionName, accessStrategy );
                    cacheAccess.addCacheRegion( cacheRegionName, entityRegion );
                }
            }

            NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null;
            if ( model.hasNaturalId() && model.getNaturalIdCacheRegionName() != null ) {
                final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName();
                naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName );

                if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) {
                    final CacheDataDescriptionImpl cacheDataDescription = CacheDataDescriptionImpl.decode( model );

                    NaturalIdRegion naturalIdRegion = null;
                    try {
                        naturalIdRegion = regionFactory.buildNaturalIdRegion(naturalIdCacheRegionName, properties,
                                cacheDataDescription);
                    }
                    catch ( UnsupportedOperationException e ) {
                        LOG.warnf(
                                "Shared cache region factory [%s] does not support natural id caching; " +
                                        "shared NaturalId caching will be disabled for not be enabled for %s",
                                regionFactory.getClass().getName(),
                                model.getEntityName()
                        );
                    }

                    if (naturalIdRegion != null) {
                        naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() );
                        entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy );
                        cacheAccess.addCacheRegion(  naturalIdCacheRegionName, naturalIdRegion );
                    }
                }
            }

            EntityPersister cp = persisterFactory.createEntityPersister(
                    model,
                    accessStrategy,
                    naturalIdAccessStrategy,
                    this,
                    mapping
            );
            entityPersisters.put( model.getEntityName(), cp );
            classMeta.put( model.getEntityName(), cp.getClassMetadata() );
        }
//        this.classMetadata = Collections.unmodifiableMap(classMeta);
        for (Map.Entry<String, ClassMetadata> entry : classMeta.entrySet()) {
            this.classMetadata.put(entry.getKey(), entry.getValue());
        }

        Map<String,Set<String>> tmpEntityToCollectionRoleMap = new HashMap<String,Set<String>>();
//        collectionPersisters = new HashMap<String,CollectionPersister>();
        Map<String,CollectionMetadata> tmpCollectionMetadata = new HashMap<String,CollectionMetadata>();
        Iterator collections = cfg.getCollectionMappings();
        while ( collections.hasNext() ) {
            Collection model = (Collection) collections.next();
            final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName();
            final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() );
            CollectionRegionAccessStrategy accessStrategy = null;
            if ( accessType != null && settings.isSecondLevelCacheEnabled() ) {
                LOG.tracev( "Building shared cache region for collection data [{0}]", model.getRole() );
                CollectionRegion collectionRegion = regionFactory.buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl
                        .decode( model ) );
                accessStrategy = collectionRegion.buildAccessStrategy( accessType );
                entityAccessStrategies.put( cacheRegionName, accessStrategy );
                cacheAccess.addCacheRegion( cacheRegionName, collectionRegion );
            }
            CollectionPersister persister = persisterFactory.createCollectionPersister(
                    cfg,
                    model,
                    accessStrategy,
                    this
            ) ;
            collectionPersisters.put( model.getRole(), persister );
            tmpCollectionMetadata.put( model.getRole(), persister.getCollectionMetadata() );
            Type indexType = persister.getIndexType();
            if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) {
                String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this );
                Set roles = 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 = tmpEntityToCollectionRoleMap.get( entityName );
                if ( roles == null ) {
                    roles = new HashSet();
                    tmpEntityToCollectionRoleMap.put( entityName, roles );
                }
                roles.add( persister.getRole() );
            }
        }
//        collectionMetadata = Collections.unmodifiableMap( tmpCollectionMetadata );
        for (Map.Entry<String, CollectionMetadata> entry : tmpCollectionMetadata.entrySet()) {
            collectionMetadata.put(entry.getKey(), entry.getValue());
        }
        Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator();
        while ( itr.hasNext() ) {
            final Map.Entry entry = ( Map.Entry ) itr.next();
            entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) );
        }
//        collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap );
        for (Map.Entry<String, Set<String>> entry : tmpEntityToCollectionRoleMap.entrySet()) {
            collectionRolesByEntityParticipant.put(entry.getKey(), entry.getValue());
        }

        //Named Queries:
        namedQueries.putAll(cfg.getNamedQueries());
        namedSqlQueries.putAll(cfg.getNamedSQLQueries());
        sqlResultSetMappings.putAll(cfg.getSqlResultSetMappings());
        imports.putAll(cfg.getImports());

        // after *all* persisters and named queries are registered
        Iterator iter = entityPersisters.values().iterator();
        while ( iter.hasNext() ) {
            final EntityPersister persister = ( ( EntityPersister ) iter.next() );
            persister.postInstantiate();
            registerEntityNameResolvers( persister );

        }
        iter = collectionPersisters.values().iterator();
        while ( iter.hasNext() ) {
            final CollectionPersister persister = ( ( CollectionPersister ) iter.next() );
            persister.postInstantiate();
        }

        //JNDI + Serialization:

//        name = settings.getSessionFactoryName();
//        try {
//            uuid = (String) UUID_GENERATOR.generate(null, null);
//        }
//        catch (Exception e) {
//            throw new AssertionFailure("Could not generate UUID");
//        }
//        SessionFactoryRegistry.INSTANCE.addSessionFactory(
//                uuid,
//                name,
//                settings.isSessionFactoryNameAlsoJndiName(),
//                this,
//                serviceRegistry.getService( JndiService.class )
//        );

        LOG.debug( "Instantiated session factory" );

        settings.getMultiTableBulkIdStrategy().prepare(
                jdbcServices,
                buildLocalConnectionAccess(),
                cfg.createMappings(),
                cfg.buildMapping(),
                properties
        );


        if ( settings.isAutoCreateSchema() ) {
            new SchemaExport( serviceRegistry, cfg )
                    .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) )
                    .create( false, true );
        }
        if ( settings.isAutoUpdateSchema() ) {
            new SchemaUpdate( serviceRegistry, cfg ).execute( false, true );
        }
        if ( settings.isAutoValidateSchema() ) {
            new SchemaValidator( serviceRegistry, cfg ).validate();
        }
        if ( settings.isAutoDropSchema() ) {
            schemaExport = new SchemaExport( serviceRegistry, cfg )
                    .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) );
        }

//        currentSessionContext = buildCurrentSessionContext();

        //checking for named queries
        if ( settings.isNamedQueryStartupCheckingEnabled() ) {
            final Map<String,HibernateException> errors = checkNamedQueries();
            if ( ! errors.isEmpty() ) {
                StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " );
                String sep = "";
                for ( Map.Entry<String,HibernateException> entry : errors.entrySet() ) {
                    LOG.namedQueryError( entry.getKey(), entry.getValue() );
                    failingQueries.append( sep ).append( entry.getKey() );
                    sep = ", ";
                }
                throw new HibernateException( failingQueries.toString() );
            }
        }

        // this needs to happen after persisters are all ready to go...
//        this.fetchProfiles = new HashMap();
        itr = cfg.iterateFetchProfiles();
        while ( itr.hasNext() ) {
            final org.hibernate.mapping.FetchProfile mappingProfile =
                    ( org.hibernate.mapping.FetchProfile ) itr.next();
            final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() );
            for ( org.hibernate.mapping.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) {
                // resolve the persister owning the fetch
                final String entityName = getImportedClassName( mappingFetch.getEntity() );
                final EntityPersister owner = entityName == null
                        ? null
                        : entityPersisters.get( entityName );
                if ( owner == null ) {
                    throw new HibernateException(
                            "Unable to resolve entity reference [" + mappingFetch.getEntity()
                                    + "] in fetch profile [" + fetchProfile.getName() + "]"
                    );
                }

                // validate the specified association fetch
                Type associationType = owner.getPropertyType( mappingFetch.getAssociation() );
                if ( associationType == null || !associationType.isAssociationType() ) {
                    throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" );
                }

                // resolve the style
                final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() );

                // then construct the fetch instance...
                fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle );
                ((Loadable) owner).registerAffectingFetchProfile( fetchProfile.getName() );
            }
            fetchProfiles.put( fetchProfile.getName(), fetchProfile );
        }

//        this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy();
//        this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( cfg.getCurrentTenantIdentifierResolver() );
//        this.transactionEnvironment = new TransactionEnvironmentImpl( this );
//        this.observer.sessionFactoryCreated( this );
    }

使用:

private SessionFactory sessionFactory;

	@Override
	protected void setUp() throws Exception {
		// A SessionFactory is set up once for an application
        sessionFactory = new Configuration()
                .configure() // configures settings from hibernate.cfg.xml
                .buildSessionFactory();

	}

	@Override
	protected void tearDown() throws Exception {
		if ( sessionFactory != null ) {
			sessionFactory.close();
		}
	}


public void testBasicCode() {
        SessionFactoryImpl sf = (SessionFactoryImpl) sessionFactory;
        Configuration cfg = new Configuration();
        cfg.addFile(new File("Code.hbm.xml"));
        cfg.buildMappings();
        sf.mergeConfiguration(cfg);
        Session session = sf.openSession();

        session.beginTransaction();
        Map code = new HashMap();
        code.put("name", "jk");
        code.put("title", "哈哈");
        session.save("Code", code);
        session.getTransaction().commit();

        session = sf.openSession();
        session.beginTransaction();
        List result = session.createQuery("from Code").list();
        for (Object obj : result) {
            System.out.println("Code ("+obj+")");
        }
        session.getTransaction().commit();

    }


转载于:https://my.oschina.net/juqkai/blog/150229

相关文章:

  • java多线程synchronized,wait,notify的大致用法
  • linux知识汇总
  • 自己做的笔试题
  • 风斗
  • localhost:3000显示rails首页的波折
  • 原型模式 objective-c 版
  • 数数http://acm.nyist.net/JudgeOnline/problem.php?pid=198
  • [源码]RandomId 生成随机字符串
  • 用户使用Citrix 应用时无法使用本地输入法
  • Android用户界面开发:TabHost
  • 柔性屏幕来袭,概念到落地急需杀手级应用推广普及
  • 关于网站编程Alex
  • 微信公众平台搭建与开发揭秘迷你书
  • java_泛型,设置类型通配符的上限
  • 持保留意见
  • 2017年终总结、随想
  • 5分钟即可掌握的前端高效利器:JavaScript 策略模式
  • flutter的key在widget list的作用以及必要性
  • git 常用命令
  • Hexo+码云+git快速搭建免费的静态Blog
  • JavaScript实现分页效果
  • JavaWeb(学习笔记二)
  • MySQL主从复制读写分离及奇怪的问题
  • pdf文件如何在线转换为jpg图片
  • QQ浏览器x5内核的兼容性问题
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • Spring-boot 启动时碰到的错误
  • XForms - 更强大的Form
  • 大快搜索数据爬虫技术实例安装教学篇
  • 讲清楚之javascript作用域
  • 看域名解析域名安全对SEO的影响
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 通过来模仿稀土掘金个人页面的布局来学习使用CoordinatorLayout
  • 一道闭包题引发的思考
  • 译自由幺半群
  • 由插件封装引出的一丢丢思考
  • 测评:对于写作的人来说,Markdown是你最好的朋友 ...
  • ​低代码平台的核心价值与优势
  • #大学#套接字
  • (1)虚拟机的安装与使用,linux系统安装
  • (AngularJS)Angular 控制器之间通信初探
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (十五)使用Nexus创建Maven私服
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (一)80c52学习之旅-起始篇
  • .apk文件,IIS不支持下载解决
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .net core 依赖注入的基本用发
  • .NET 指南:抽象化实现的基类
  • .NET 中创建支持集合初始化器的类型
  • .NET简谈设计模式之(单件模式)
  • .NET开源项目介绍及资源推荐:数据持久层 (微软MVP写作)
  • @AutoConfigurationPackage的使用
  • @NestedConfigurationProperty 注解用法