views:

44

answers:

1
+1  A: 

Update & delete queries are considered Bulk Updates in JPA, and have different rules. Bulk updates execute directly on the database the persistence context (EntityManager) will not be updated with these changes. So when you query the persistence context it finds a matching entity - unknowingly returning stale data.

The JPA specification puts it like this :

Caution should be used when executing bulk update or delete operations because they may result in inconsistencies between the database and the entities in the active persistence context. In general, bulk update and delete operations should only be performed within a transaction in a new persistence con- text or before fetching or accessing entities whose state might be affected by such operations.

You have a couple of options on how to fix the problem.

Rewrite the first query to return the entity instead of just the id. and modify the entity. Something like this should work

public List<Domain> doInJpa(EntityManager entityManager) throws PersistenceException {
    Calendar dayBefore = Calendar.getInstance();
    dayBefore.setTime(timestamp);
    dayBefore.add(Calendar.HOUR, -24);

    List<Domain> domains = entityManager.createQuery("SELECT d FROM domain d WHERE d.crawlDate IS NULL and (d.lastRead IS NULL OR d.lastRead <= :dayBefore ) ")
        .setParameter("dayBefore", dayBefore.getTime())
        .setMaxResults(maxAllowedItems)
        .getResultList();

    if(domains.isEmpty()) {
        return new ArrayList<Domain>();
    }

    for(Domain d : domains) { 
        d.setLastRead(timestamp);
    }

    return domains;     
}

Now you're down to one query, the entities will be synchronized with the persistence context and your test should pass.

Failing that you can work around the issue with bulk updates by calling entityManager.refresh() on each domain - the refresh method will update the entity with the latest state from the database.

Mike