views:

155

answers:

2

UPDATE: EXAMPLE TO CLARIFY I'm going to put an example of what's happening just to clarify the situation in my Spring + Hibernate application. Imagine I have this two entities (suppose getters and setters exists too)

@Entity
public class Class1(){
  private Integer id;

  @OneToOne
  private Class2 object2;
}

@Entity
public class Class2(){
  private Integer id;

  @OneToOne
  private Class1 object2;
}

So in my database I have two tables to map every instance of each object. Suppose I have stored in the database these objects:

  • objectA (class Class1) : id = 1 , object2 = objectB
  • objectB (class Class2) : id = 2 , object2 = objectA
  • objectC (class Class2) : id = 3 , object2 = null which means A anb B are linked. Suppose now I want to link objectA to objectC. It means I have to delete the link in the objectB too.

For doing this I do the folowing:

//I get the objectA from database
Class1 storedObjectA = myservice.find(objectAId);
//Now in storedObject1 I have the same as what it is stored as objectA

//I change only the object2 attribute of it
storedObject1.setObject2(objectC);

//I search again in the database to see objectA
Class1 reStoredObjectA = myservice.find(objectAId);

restoredObjectA now is:

  • restoredObjectA (class = Class1) id = 1, object2 = objectC

though in the database there is:

  • restoredObjectA (class = Class1) id = 1, object2 = objectB

The method find has not searched in the database and I have gotten the previous search though I have my query and second level caches disabled. The method find only goes to the DAO where it executes on the entityManager.find(Class1.class, id) How can I make my second find searchs in the database?

Thanks


(Full explanation)

Hello,

I have an application which uses Spring 3 and Hibernate. I have an entity named Class1 which is stored in a database. This entity has a OneToOne link to another entity called Class2. Class2 has another OneToOne Link to Class1, and both links have unique property set to true.

I have the following code in my controller:

//I have an object called dataFromUser which is instance of Class1 and
// it is obtained via @ModelAttribute annotation from a form

Integer id = dataFromUser.getId();

//I get correctly the stored object from the database
Class1 storedData = myService.find(id); //this will call em.find of hibernate

//I set to the stored data the attribute I want to change
storedData.setObject2();

//I save again the object
myService.save(storedData);

The method save in myService will use the entity manager to persist the data, but before that it will check the previous association between Class1 object and Class2 object to delete it in case a new Class2 Object has set to the instance of Class1. For that reason I have to call find method again to see what's in my database

In the Service:

@Transactional
public void save(Class1 object1){
   Class1 objectFromDB =  myDAO.find(object1.getId());
   // ....  update the old object and save
}

The problem is that objectFromDB in the Service is not the same as when I did myService.find(id) in the controller. The problem is that it is not looking for it in the database but it is searching in memory. I know it because there is no SQL statement logged when the second find() method is called. As I had done setObject2() on the storedData object I get exactly this object when I call find method for the second time, and the database doesn't contain this because it hasn't been persisted yet.

I have tried to disable Cache in my configuration just to try, but it is still happening. I have a ehCache with this configuration:

In persistence.xml I have this properties (I have set to false both caches):

    <properties>
     <!-- Hibernate 3.5.0 - try org.hibernate.cache.* package -->
  <property name="hibernate.cache.provider_class"
               value="net.sf.ehcache.hibernate.SingletonEhCacheProvider" />
   <property name="hibernate.cache.use_query_cache" value="false" />
  <property name="hibernate.cache.use_second_level_cache" value="false" />
  <property name="hibernate.generate_statistics" value="true" />
  <property name="hibernate.cache.use_structured_entries" value="false" />
  <property name="hibernate.format_sql" value="true" />
  <!-- http://www.jroller.com/eyallupu/entry/hibernate_s_hbm2ddl_tool -->
  <!-- create, create-drop, update, validate -->
  <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>  

In my ehcache.xml I have set to 0 maxElementsInMemory and overflowToDisk to false to disable it too.

Is there any way to avoid this situation?

Thanks.

A: 

I'm not sure I understood correctly, but just in case ...


There are two methods to load an object. There is a difference if the object is not in the current memory context:

  • One goes for sure to the database, returns the instance if it exists or null otherwise.
  • The other merely creates a Proxy with the correct id, without going immediately to the database, and will process it as required in later operations (possibly when flushing).

You seem to be using the second one, maybe you could try the first and see if it solves your problem?

KLE
A: 

OK, I find it out. The problem is that hibernate looks for the objects in its Session before searching in the database. so I had to detached the object to the session before modifying it. To do so in hibernate:

    //being em my EntityManager instance
    Session session = (Session) em.getDelegate();
    session.evict(plan); 
    //Now the find object will not get the object wich is in session 
    //but the one in database
Javi