Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
285 views
in Technique[技术] by (71.8m points)

java - postInstantiate buildSessionFactory slow/memory huge database

Having an ERP database with more than 520 tables, the postInstanciate of EntityPersister is very slow and its consuming more than 512M which is to much for only one session Factory, the application become very slow.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I can't post all changes, but here the ideas :

1_ postInstanciate create many Entiy Loaders for all entities and collections (many type of loader for each entity and each collection), this operation should be done on demande, entity or collection loader should be created when its needed, not during the build of session factory, even if you have 500 entities it dosent mean that the user will load data from each entity.

    private Map LoaderMap = new LoaderMap();//instead Hashmap  
    class LoaderMap extends HashMap{
        @Override
        public Object get(Object key) {         
            Object obj = super.get(key);
            if (obj==null){
                boolean disableForUpdate = getSubclassTableSpan() > 1 &&
                        hasSubclasses() &&
                        !getFactory().getDialect().supportsOuterJoinForUpdate();

                switch (key.toString()) {
                case "NONE":
                    obj = createEntityLoader( LockMode.NONE );
                    break;
                case "READ":
                    obj = createEntityLoader( LockMode.READ );                  
                    if (disableForUpdate){
                        put(LockMode.UPGRADE, obj );
                        put(LockMode.UPGRADE_NOWAIT, obj );
                        put(LockMode.UPGRADE_SKIPLOCKED, obj );
                        put(LockMode.FORCE, obj );                                          
                        put(LockMode.PESSIMISTIC_READ, obj );
                        put(LockMode.PESSIMISTIC_WRITE, obj );
                        put(LockMode.PESSIMISTIC_FORCE_INCREMENT, obj );                        
                    }
                    break;
                case "UPGRADE":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.UPGRADE );
                case "UPGRADE_NOWAIT":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.UPGRADE_NOWAIT );
                case "UPGRADE_SKIPLOCKED":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.UPGRADE_SKIPLOCKED );
                case "FORCE":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.FORCE );
                case "PESSIMISTIC_READ":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.PESSIMISTIC_READ );
                case "PESSIMISTIC_WRITE":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.PESSIMISTIC_WRITE );
                case "PESSIMISTIC_FORCE_INCREMENT":
                    if (disableForUpdate)
                        obj = get("READ");                       
                    else
                        obj = createEntityLoader( LockMode.PESSIMISTIC_FORCE_INCREMENT );
                case "OPTIMISTIC":
                    obj = createEntityLoader( LockMode.READ );
                    break;
                case "OPTIMISTIC_FORCE_INCREMENT":
                    obj = createEntityLoader( LockMode.READ );
                    break;
                case "merge":
                    obj = new CascadeEntityLoader( AbstractEntityPersister.this, CascadingActions.MERGE, getFactory() );
                    break;                  
                case "refresh":
                    obj = new CascadeEntityLoader( AbstractEntityPersister.this, CascadingActions.REFRESH, getFactory() );
                    break;  
                default:
                    break;
                }
                put(key, obj);
            }
            return obj;
        }
    }
    //Relational based Persisters should be content with this implementation
    protected void createLoaders() {
        if (true)
            return;
....
       }

2_ DirectPropertyAccessor is calling getDeclaredField twice once for the buildGetter Method and the second for buildSetter, using map is a good optimization.

public static final Map<Double, Field> tmp = new HashMap<Double, Field>();
    private static Field getField(Class root, Class clazz, String name) throws PropertyNotFoundException {
        if ( clazz==null || clazz==Object.class ) {
            throw new PropertyNotFoundException("field [" + name + "] not found on " + root.getName()); 
        }               
        double hash = name.hashCode() + clazz.hashCode()*1.1;
        Field field = tmp.get( hash );
        if (field==null)
        try {
            field = clazz.getDeclaredField(name);
            tmp.put( hash, field );
        }
        catch (NoSuchFieldException nsfe) {
            field = getField( root, clazz.getSuperclass(), name );
        }
        field.setAccessible(true);
        return field;
    }

Response to Ulrich Scholz: I add a jar containning all fixed Classes to the project, in my case its Webapp application deployed on Tomcat, all you need is to fix the loading order of the Jars using :

<Context>
<Resources>
      <PreResources className="org.apache.catalina.webresources.FileResourceSet"
                base="${catalina.base}/webapps/AGIWERP/WEB-INF/lib/AAACLZ-1.0.jar"
                webAppMount="/WEB-INF/lib/AAACLZ-1.0.jar" />
</Resources>

</Context>

This mean your classes should be loaded before the original ones


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...