1

My Application has a service will polls internally for job output. It polls till the job status changes from "In-progress" to "Completed". Another system is going to update the job status to "Completed" once it processes the job.

The problem here is, first time when the job status is polled from DB the status as "In-progress". But later even when the job status is changed by other process I still see it as "In-progress". The issue is not with DB Isolation level(Repeatable Read) as my hibernate queries are executing out of transaction. I suspect the results are cached and when same query is executed in the same session, I'm getting the cached results.

How can I get the updated data from DB when same query is executed in same session multiple times.

Regards, Chandu

chandu
  • 403
  • 1
  • 6
  • 15

1 Answers1

2

UPDATE

As per the comments, it is a Spring Boot application that uses Spring JPA data. And the service class checks for the status every 5 minutes with a loop in it. i.e., which effectively is in a same transaction i.e., same session.

And so, unless we call refresh() or evict() and reload we won't be able to see the updated state from the database.

But the problem is that the CrudRepository doesn't expose any methods like refresh() that we can call on entity manager.

So the option is to the CrudRepository and add a method say refreshEntity(...). This method will internally call entityManager.refresh(). Finally the service loop can invoke this refreshEntity(..) method and get the updated data.

As an example:

public interface MyStatusRepository {
   void refreshEntity(StatusEntity se);
}

public interface StatusRepository extends CrudRepository<StatusEntity, Long>, MyStatusRepository {
    ...
}

@Repository
public class MyStatusRepositoryImpl implements MyStatusRepository {
    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void refreshEntity(StatusEntity se); {
        entityManager.refresh(se);
    }
    ...
}

More information on Extending repository can be found at the above link.

Other option was, instead of extending the CrudRepository, autowire the entityManager in the service class itself and call the refresh() on it. This works as well, but would be a deviation from the existing design.

  • I don't have second level cache enabled. I'm using spring boot with hibernate hence I don't explicitly call factory.openSession() to open session. I have DAO layer which extends CrudRepository. Using spring autowired bean I call methods like save() , fndByName() etc to fetch and update results. How can I make sure I evict() or refresh() session. – chandu Mar 30 '16 at 16:07
  • @chandu That is bit confusing. If you are using CrudRepository you won't be even using `session` directly. correct? When you say `service` is polling, is it a scheduled job like `@scheduled` annotation on it or who calls this service to poll the db. Can you show the code of the `service` code where you are polling for the status changes? – Madhusudana Reddy Sunnapu Mar 30 '16 at 16:21
  • You are right, I don't use the session directly. My service calls the DB in a loop and check the status. It if is "InProgress", the thread sleeps for 5 seconds and it queries the DB again. In the mean time if job status is updated, I break the loop and return result. Hope it is clear now – chandu Mar 30 '16 at 16:28
  • @chandu So it is not a scheduled job and someone calls this `service` only once and it continues to check the status in a loop.And I think your `service` is running under same transaction which effectively means same session. correct? – Madhusudana Reddy Sunnapu Mar 30 '16 at 16:34
  • correct I have a service which runs out of transaction and calls a method in another service layer(second service layer). I tried second service layer with all possible transaction propagations like NOT_SUPPORTED, REQUIRES_NEW, REQUIRED. But still the second service method gives me same result as that of first call. – chandu Mar 30 '16 at 16:41
  • To make sure that my first service is not starting transaction, I marked method in second service's propagation as MANDATORY which throws error saying no existing transaction(by this I'm sure the main service is running out of transaction). With this I came to conclusion that the issue is not with REATABLE_READ isolation which gives same results within trasaction – chandu Mar 30 '16 at 16:41
  • @chandu Got it. Even calling the a method in another service doesn't help because it is always that same single instance we are using. The problem lies in the fact that `CrudRepository` doesn't expose any methods like `refresh`.So you need to extend the `CrudRepository` and add a method like `refreshEntity()` that will internally call `entityManager.refresh()`.And with this, our `service` will call `refresh` method and this will get us the updated entity. Look at http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations . This shoudl help – Madhusudana Reddy Sunnapu Mar 30 '16 at 16:45
  • Yeah extending CrudRepository would be one option but I'm trying out some other opertion where in my service layer I'm going to get entity manager as follows. @PersistenceContext EntityManager entityManager; And before querying DB I call evict like this entityManager.unwrap(Session.class).evict(obj); – chandu Mar 30 '16 at 16:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107762/discussion-between-madhusudana-reddy-sunnapu-and-chandu). – Madhusudana Reddy Sunnapu Mar 30 '16 at 16:58