Извините заранее за длинный пост.Я работаю с Java WebApplication, который использует Spring (2.0, я знаю ...) и Jpa с Hibernateimplementation (используя hibernate 4.1 и hibernate-jpa-2.0.jar).У меня возникают проблемы при получении значения столбца из таблицы БД (MySql 5) после его обновления.Это моя ситуация (упрощенно, но в этом ее суть):
Таблица KcUser :
Id:Long (primary key)
Name:String
.
.
.
Contract_Id: Long (foreign key, references KcContract.Id)
Таблица KcContract :
Id: Long (primary Key)
ColA
.
.
ColX
На моем сервере у меня есть что-то вроде этого:
MyController {
myService.doSomething();
}
MyService {
private EntityManager myEntityManager;
@Transactional(readOnly=true)
public void doSomething() {
List<Long> IDs = firstFetch(); // retrieves some users IDs querying the KcContract table
doUpdate(IDs); // updates a column on KcUser rows that matches the IDs retrieved by the previous query
secondFecth(IDs); // finally retrieves KcUser rows <-- here the returned rows contains the old value and not the new one i updated in the previous method
}
@Transactional(readOnly=true)
private List<Long> firstFetch() {
List<Long> userIDs = myEntityManager.createQuery("select c.id from KcContract c" ).getResultList(); // this is not the actual query, there are some conditions in the where clause but you get the idea
return userIDs;
}
@Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW)
private void doUpdate(List<Long> IDs) {
Query hql = myEntityManager().createQuery("update KcUser t set t.name='newValue' WHERE t.contract.id IN (:list)").setParameter("list", IDs);
int howMany = hql.executeUpdate();
System.out.println("HOW MANY: "+howMany); // howMany is correct, with the number of updated rows in DB
Query select = getEntityManager().createQuery("select t from KcUser t WHERE t.contract.id IN (:list)" ).setParameter("list", activeContractIDs);
List<KcUser> users = select.getResultList();
System.out.println("users: "+users.get(0).getName()); //correct, newValue!
}
private void secondFetch(List<Long> IDs) {
List<KcUser> users = myEntityManager.createQuery("from KcUser t WHERE t.contract.id IN (:list)").setParameter("list", IDs).getResultList()
for(KcUser u : users) {
myEntityManager.refresh(u);
String name = u.getName(); // still oldValue!
}
}
}
Странно то, что если я прокомментирую вызов первого метода (myService.firstFetch()
) и вызову два других методас постоянным списком идентификаторов, я получаю правильное новое значение KcUser.name в secondFetch(
) метод.
Я не очень опытен с Jpa и Hibernate, но я подумал, что это может быть проблема с кешем, поэтому я попытался:
- , используя myEntityManager.flush () после обновления
- очистка кэша с помощью myEntityManager.clear () и myEntityManager.getEntityManagerFactory (). EvictAll ();
- очистка кэша с помощью hibernate Session.clear ()
- с использованием myEntityManager.обновить сущности KcUser
- с использованием собственных запросов (myEntityManager.createNativeQuery ("")), которые, на мой взгляд, не должны включать в себя кеш
Ничего из этого не сработало, и я всегда получал возвратстарое значение KcUser.name в методе secondFetch()
.
До сих пор работали только:
, делающие метод firstFetch()
общедоступным и перемещая его вызовза пределами myService.doSomething (), делая что-то подобное в MyController:
List<Long> IDs = myService.firstFetch();
myService.doSomething(IDs);
с использованием нового EntityManager в secondFetch(
), делая что-токак это:
EntityManager newEntityManager = myEntityManager.getEntityManagerFactory().createEntityManager();
и использование его для выполнения последующего запроса для извлечения пользователей из БД
Используя любой из двух последних методов, второй выбор работает нормально, и я получаю пользователейс обновленным значением в столбце «имя».Но я хотел бы знать, что на самом деле происходит и почему ничего другого не сработало: если это на самом деле проблема с кешем, просто .clear()
или .refresh()
должны были бы работать, я думаю.Или, может быть, я совершенно не прав, и это вообще не связано с кешем, но потом я немного теряюсь в том, что на самом деле может происходить.
Боюсь, может быть что-то не так в том, как мы используем hibernate / jpa, что может укусить нас в будущем.Любая идея, пожалуйста?Скажите, если вам нужно больше деталей и спасибо за вашу помощь.