Hello everybody,
I'm wondering, how to refresh efficiently a set (or even better s subset) of objects which is already present in the first-level cache (session cache).
The example scenario is pretty simple: a fat-client presents a list of customers and a single refresh button. Whenever the user clicks "refresh" the list should be updated based on the most current database state.
Side conditions:
- One Hibernate Session should be used
- Each customer instance hold in memory should only get thrown away if it is deleted in the database; if the instance gets stale, it's attributes have to get updated
The problem:
Code:
private void retrieve_a() {
Query q = session.createQuery("from Customer as cust");
listA = q.list();
tx.commit();
}
Every time this code is executed, listA might not contain a consistent view of the database state, as there might be stale objects:
t1: retrieve_a() --> listA {(id=1,name=frank,seq=2) )}
t2: -- some concurrent database user inserts a new tuple (id=2 ...)
t3: retrieve_a() --> listA {(id=1,name=frank,seq=2),(id=2,name=joe,seq=1)}
t4: -- some concurrent database user updates (id=1,name=bart,seq=3) and inserts (id=3,...)
t5: retrieve_a() --> listA {(id=1,name=frank,seq=2),...,(id=3,name=homer,seq=1)}
At t5 there is a stale object (cusomer:id=1) hold in memory.
This behaviour is well documented, as Hibernate uses its first-level cache.
There are of course some simple solutions:
a) get rid of all cached objects before querying the database (evicting them: session.evict(...) )
b) within one transaction boundary: first query the database, second refresh each object in the result-set (query.list) (as shown in retrieve_c() )
By using solution a) everytime a query is executed, all instances are thrown away and new ones are created. I really want to avoid this!
By using solution b) a potential performance problem might occur, as for each element of listA a "select from where" has to be performed, to check, if some changes occured. If there are lots of instances in listA ...
QuestionMy question is, how to efficiently refresh the first-level cache? Is there a way to 'mark' a whole set of objects to get refreshed in an efficient way?
Hibernate version: 3.0.5
Mapping documents:Code:
<hibernate-mapping>
<class name="Customer" table="customer">
<id name="id" column="id"> <generator class="increment"/></id>
<version name="sequence" column="sequence"/>
<property name="name" column="name"/>
</class>
</hibernate-mapping>
Code snippet:Code:
class Cusomer {
public int id;
public int sequence;
public String name;
}
class Test {
...
private List listA;
...
private void init(){
testA();
refreshGui();
}
public void buttonCallBack(){
testA();
refreshGui();
}
private void testA(){
//t0
retrieve_a();
//t1
}
private void retrieve_a() {
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Customer as cust");
listA = q.list();
tx.commit();
}
private void retrieve_b(){
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Customer as cust");
q.setLockMode("cust",LockMode.READ);
listA = q.list();
tx.commit();
}
private void retrieve_c(){
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
Query q = session.createQuery("from Customer as cust");
listA = q.list();
//pseudocode begin --
for all objects in listA:
session.refresh( ... )
//pseudocode end --
tx.commit();
}
[/i]