开发者

Keeping Hibernate Collections in Memory

I am running into a problem managing my Hibernate-backed collections. The problem is illustrated in the code below; briefly,

  1. A single session and transaction are started.
  2. All instances of ClassA are loaded and walked to force Hibernate to load all instances of ClassC. At this point all instances of ClassC actually load via lazy fetching.
  3. In the same transaction and session, all instances of ClassB are loaded.
  4. All instances of ClassC are no longer available (the containing collections are empty) and do not lazy load if requested.

What's the best way to load up the data sets needed and keep them in memory?

Notes:

The project is in rapid-prototyping mode so I am using a single session and single transaction to load up two big chunks of the application's data. This is also a desktop application so the use of a single session and transaction may not even be a problem in the long run if the code were working.

I set up ehcache and the debugger showing that Hibernate found the ehcache config file. The cache is set such that

maxElementsInMemory="5000000"
eternal="true" 

the timeouts are set to 20 mins, even though eternal is set true, just to be sure the session isn't timing out.

The data set size is not particularly large, about 100k records. The Hibernate 3.0 module packaged with NetBeans was use to create the class templates from a data model.


The mapping file looks roughly like this:

<hibernate-mapping>
  <class catalog="myCatalog" name="ClassA" table="classA">
    <id ... </id>
    <set inverse="true" name="classCs" sort="natural">
      <key>
        <column length="12" name="mykey" not-null="true"/>
      </key>
      <one-to-many class="ClassC"/>
    </set>
  </class>
</hibernate-mapping>

Class definitions:

@Entity
@Table(name = "classA", catalog = "myCatalog")
public class ClassA implements java.io.Serializable {
   private SortedSet<ClassC> classCs = new TreeSet<ClassC>();

   @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "ClassA")
   public SortedSet<ClassC> getClassCs() {
      return this.classCs;
   }
}

@Entity
@Table(name = "classB", catalog = "myCatalog")
public class ClassB implements java.io.Serializable {
    // ... It is possible to walk collections in this class to reach some instances of classA.
}

public class ClassC implements java.io.Serializable {
    // ... contains no collections
}

Manifestation of problem:

// in Hibernate Util   
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();

public static void main(String[] args) {
    Application.session = HibernateUtil.getSessionFactory().openSession();
    Application.tx = session.beginTransaction();

    // Load data set 'A' and force collections to load
    List<ClassA> listClassA = new ArrayList<ClassA>();
    Query q = Application.session.createQuery("from ClassA as a").setReadOnly(true);
    Iterator<ClassA> iterator = q.list().iterator();
    while (iterator.hasNext()) {
        ClassA ca = (ClassA)iterator.next();
        // force member collection to load -- at present this is necessary even though FetchType is EAGER
        ca.getClassCs(); 
        listClassA.add(ca);
    }           

    // The collections of classCs are in are in memory here
    for(ClassA a : listClassA){
        log.info(a.getId() + "-" + a.getClassCs().size());
    } 

    // Load data set 'B'
    List<ClassB> listClassB = new ArrayList<ClassB>();
    String sq = "from classB as b where ...";
    Query q = Application.session.createQuery(sq);
    listClassB.addAll(q.list());

开发者_开发百科    // The collections of classCs are NOT in memory and touching collections does not force reload
    // The collections exist but now all have size zero
    for(ClassA a : listClassA){
        log.info(a.getId() + "-" + a.getClassCs().size());
    }
    return;
}


I turns out that Hibernate can optionally flush the session cache before each query. One of the settings to control the session cache is session.setFlushMode(). In Hibernate 3.2.5, setting flush mode to:

FlushMode.COMMIT or FlushMode.MANUAL

achieves the desired result. I found this while reading "Hibernate in Action".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜