views:

487

answers:

3

I am hitting an issue with my Hibernate backed Jpa queries returning data that is not up to date. I assume it is an issue with pulling data from the cache instead of the database itself.

For example, I will change and persist an object on one page and then go back to the previous page, which lists rows of the database, and it will show the objects as they existed prior to the change. I can see my query fire from my DAO in my logs and I can go into the database and see that the changes have been persisted, but JPA is not pulling up to date data from the database when I move on to the next page.

I believe there might be some kind of session caching at work, as I will not see an updated database view when I load the page up in another web browser.

How do I fix this issue?

EDIT: I've done some follow up testing, including logging on my controller to make sure my MVC framework (Spring MVC) isn't caching anything. It isn't, even on the controller level it sees out of date database information.


Here is the mapping snippet from my ORM entity file;

private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = true)
@Column(name = "ID", nullable = false)
private Integer id;
@Basic(optional = false)
@Column(name = "Name", nullable = false, length = 100)
private String name;
@Basic(optional = false)
@Column(name = "DayOffset", nullable = false)
private int dayOffset;
@Basic(optional = false)
@Column(name = "StartTime", nullable = false, length = 5)
private String startTime;
@Basic(optional = false)
@Column(name = "Enabled", nullable = false)
private boolean enabled;
@Basic(optional = false)
@Column(name = "LastTouched", insertable = false, updatable = false, nullable =
false)
@Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
@Column(name = "TouchedBy", length = 50)
private String touchedBy;
@JoinTable(name = "ReconciliationSearchRule",
joinColumns = {@JoinColumn(name = "ReconciliationId",
    referencedColumnName = "ID", nullable = false)},
inverseJoinColumns = {@JoinColumn(name = "SearchRuleId",
    referencedColumnName = "ID", nullable = false)})
@ManyToMany(fetch = FetchType.LAZY)
private Collection<SearchRule> searchRuleCollection;
@JoinColumn(name = "ServerId", referencedColumnName = "ID", nullable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Server server;
@OneToMany(mappedBy = "reconciliation")
private Collection<Report> reportCollection;
A: 

There are a couple ways of going about this:

  1. Set an eviction strategy using the @DataCache(timeout = 1000) on the entity in question and set it to something reasonable for the object type you are using.
  2. Call evict(...) on your entity or class. The implementation details of this are specific based upon what provider (e.g. Hibernate) you are using.
rynmrtn
For 1, could you explain in more detail with @DataCache would go? For 2, which class has the evict method? Thank you.
James McMahon
Hibernate Session has evict(), which isn't suitable for you ;)
Bozho
@DataCache is an annotation that you put on the class that is not refreshed (because it is cached). This annotation will instruct JPA to evict (or clear) the cache for objects of this type on the frequency specified via the timeout parameter.
rynmrtn
@rynmrtn, So you put on your entity class in the ORM layer. What is the default for @DataCache? And where can I find the java docs?
James McMahon
@rynmrtn, is @DataCache a Hibernate annotation? My IDE has no idea where to import it from and I have had no luck finding the docs for it. If it is Hibernate, I can't use it directly because I am trying to work through JPA.
James McMahon
It looks like `@DataCache` is an OpenJPA annotation. I apologize for the confusion. I have a feeling that you are going to find JPA specification to be lacking on a lot of necessary features of developing enterprise level applications. On several of my projects, JPA is targeted except in places where the specification is seriously lacking (in which case, we use Hibernate).
rynmrtn
A: 

For example, I will change and persist an object on one page and then go back to the previous page, which lists rows of the database, and it will show the objects as they existed prior to the change.

Second level cache management should be transparent, you don't have to evict() an entity manually after any update, the 2nd level cache gets invalidated for the target table "automatically" by Hibernate.

So, my question is: what do you mean by "going back to the previous page"? Do you mean using the navigator "Back" button? Did you reload the page? Can you clarify this?

Also, can you post your mapping file or annotated entity?

Pascal Thivent
Pascal, by going back I click a hyperlink that takes me to another page. I will post up some more information when I am at work Monday.
James McMahon
+1  A: 

I figured out what was going on. My DAO is being injected as a prototype (aka non-singleton) so the backing EntityManager was being created for each use of the DAO. Database changes external to the EntityManager are not registered by queries to that particular EntityManager.

Of course setting the DAO to a singleton causes other issues with the multi-threaded part of my application, but that is a whole other issue.

James McMahon