Why is an object found by id in JPA, but not through a JPQL query?
I have a JUnit 4 test case with the Spring @Transactional
annotation that saves an object, and then attempts to find it. The test case 开发者_运维技巧passes when I use this implementation:
@Override
public EventSummary findEventSummaryById(Integer id) {
return em.find(EventSummary.class, id);
}
It fails when I use this implementation (and then change which method I call in the test case):
@Override
public EventSummary findEventSummary(Integer id) {
Query query = em.createQuery("select es from EventSummary as es where es.id = :id");
query.setParameter("id", id);
EventSummary result = (EventSummary) query.getSingleResult();
return result;
}
If you are using the default flush mode (AUTO
) and if you are executing your query within a transaction, the JPA specification guarantees that a Query will not return stale or incorrect data:
3.6.2 Queries and FlushMode
The flush mode setting affects the result of a query as follows.
When queries are executed within a transaction, if
FlushModeType.AUTO
is set on theQuery
object, or if the flush mode setting for the persistence context isAUTO
(the default) and a flush mode setting has not been specified for theQuery
object, the persistence provider is responsible for ensuring that all updates to the state of all entities in the persistence context which could potentially affect the result of the query are visible to the processing of the query. The persistence provider implementation may achieve this by flushing those entities to the database or by some other means. IfFlushModeType.COMMIT
is set, the effect of updates made to entities in the persistence context upon queries is unspecified.public enum FlushModeType { COMMIT, AUTO }
If there is no transaction active, the persistence provider must not flush to the database.
Assuming that you are using AUTO
, check the transactional side.
Тhe entity is in the current session (entity manager) - it is in persistent state, waiting to be flushed. The get method first checks the contents of the session, and if not found turns to the underlying database. In your case, the entity has just been saved in the same session, so it is found and returned.
Update: it turned out the problem is using an incorrect transaction manager, hence the entity hasn't been flushed to the database. See Pascal's explanation.
in the first case, the id is an Integer
in the second, the id is a String
an Integer will never equal a String
精彩评论