Khaledvic Khaledvic - 5 months ago 21
Java Question

Hibernate EntityManger new instance not returning find results after merge

I merged an new instance (it was saved to the database) then I closed the entitymanger, opened a new one tried to find the entity but null is returned.

public <T> T merge(Object source, Event<EntitiesPersistenceEventObject<T>> event, T t, boolean notifyGenericListeners) throws PersistenceException {
EntityManager entityManager = createEntityManager();

Object id = null;

PersistenceEventType eventType;

if (id == null || (id instanceof Number && ((Number) id).equals(0))) {
eventType = PersistenceEventType.ADDED_ENTITIES;
} else {
eventType = PersistenceEventType.UPDATED_ENTITIES;
}

try {
beginTransaction(entityManager);

t = entityManager.merge(t);
id = factory.getPersistenceUnitUtil().getIdentifier(t);

commitTransaction(entityManager);
//entityManager.refresh(t);
notifyListeners(event, source, eventType, notifyGenericListeners, t);

} catch (Exception ex) {
if (entityManager != null && entityManager.isOpen()) {
// entityManager.close();
}
throw new PersistenceException(ex);
} finally {
entityManager.close();
}
closeEntityManager();

return (T) find(t.getClass(), id);
}


the find function:

public <T> T find(Class<T> type, Object id) {
EntityManager entityManager = getEntityManager();
try {
Map<String, Object> props = new HashMap<String, Object>();
props.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
//query.setHint("javax.persistence.cache.retrieveMode", "BYPASS");
T t = entityManager.find(type, id);
//entityManager.refresh(t);
return t;
} catch (Exception e) {
e.printStackTrace();
System.out.println("find exception type: " + type + " id=" + id);
throw e;
} finally {
// entityManager.close();
}
}


getEntityManger calls directly this function:

public synchronized static EntityManager getThreadEntityManager() {
//entityMangersPoolCounter = entityMangersPoolCounter % ENTITY_MANGERS_POOL_MAX_COUNT;
EntityManager em = threadLocal.get();
if (em == null || !em.isOpen()) {
factory.getCache().evictAll();
em = factory.createEntityManager();
System.out.println("Hooooooory, creating new EnTITY manager!..." + em.hashCode());

em.
setProperty("javax.persistence.sharedCache.mode", SharedCacheMode.NONE);
em.
setProperty("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
em.
setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
em.
setProperty("javax.persistence.FlushModeType", FlushModeType.AUTO);
threadLocal.set(em);

}
return em;
}


closeEntityManger just closes the threadEntityManger.

When debuging the merge fucnction a new id is generated and it's saved in the database, however when "find" is called in the last line of merge function it returns null, it's will be on a fresh entity manger since I closed the old thread Entitymanger in merge.
when debuging AbstractEntityMnagerImpl i

CacheMode cacheMode = determineAppropriateLocalCacheMode( properties );


is returning cache mode REFRESH.

Hibernate entityManger version 4.2.6.Final
Hibernate core 4.2.5.Final

Also,I enable showsql option in hibernate and it shows the select statement when excuting find but still null is returned.

Am I doing something wrong, or is it a bug in hibernate ?

EDIT: further debuging hibernate is generating good sql when I excute the generated sql query on the server, it returns one row representing the entity, but still returns empty set in hibernate!! is there any mysql caching for the connections from java ?

EDIT2: trace log http://pastebin.com/BaKzvuW3 (same when puting the query in phpmyadmin (for example) I get one row result.

EDIT3: it's very clear now that the results returned from mysql are old data. even though I'm closing entity mangers, commiting update/insert transaction, even though I tried closing transaction before read (to start a new transaction after commit the older transaction).

Answer

It appears that was an issue with mysql Isolation and consistency, it seems that calling

entityManager.getTransaction().commit();

doesn't necessarily send commit statment to mysql, or it does and it's a mysql bug.

configuring connections isolation to a level below "REPEATABLE READ", solves the issue:

        cfg.setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_READ_COMMITTED));