2

I have an oracle view in which I query my db.

create or replace view my_view as
Select cc.CCID ccid
       sm.SMCODE smcode,
       NVL(sm.smname, cc.ccname) sname
  From CC cc
 Inner Join SM sm
    On cc.id = sm.id;

I use jpa 2.1 and hibernate 4.3.7 to map my view to my entity. My entity class looks like this:

public class CCRequest implements Serializable {

    private static final long serialVersionUID = 1L;

    private String ccId;

    private String smCode;

    private String sName;
}

And my mapping xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 version="2.1">
    <entity class="CCRequest" name="CCRequest001">
        <table name="my_view"/>
        <attributes>
            <id name="ccId">
                <column name="ccid"/>
            </id>
            <basic name="smCode">
                <column name="smcode"/>
            </basic>
            <basic name="sName">
                <column name="sname"/>
            </basic>
        </attributes>
    </entity>
</entity-mappings> 

So I query my entity with jpa properly and it returns all my records. Here is the problem, when I change my data in DB asynchronously, Shockingly my jpa query returns previous records. Have I done something wrong?

A.v
  • 654
  • 4
  • 22
  • 2
    1. Do you change data in DB directly or through JPA/Hibernate methods? - Hibernate caches previous results so if you modified data directly, you won't see changes until you clear the cache. 2. If you change data using JPA/Hibernate - do you flush/commit them? 3. It may also depend how do you manage EntityManager or Session. – Justinas Jakavonis Aug 18 '16 at 17:06
  • I change data directly. But in my app there is posibility of changing data in other way than my JPA/Hibernate methods. What is th solution here. And what do you mean by saying it depends on how I manage EntityManage? – A.v Aug 18 '16 at 18:50

3 Answers3

2

Hibernate caches previous results so you should use entityManager.clear() for cleaning associated cache. It will force to execute queries again. Related threads for more details:

More about Hibernate caching:

Another option is to use entityManager.refresh(obj) to synchronize database data with session data.

Community
  • 1
  • 1
Justinas Jakavonis
  • 6,374
  • 5
  • 52
  • 88
  • Can you give me a piece of jpa/hibernate doc about this behavior? It seems a little strange to me. I think, unless some exceptional scenarios, we often want what is in our db, isn't it right? – A.v Aug 18 '16 at 20:24
  • Updated with more links. – Justinas Jakavonis Aug 18 '16 at 20:38
  • The thing that I don't understand is that if it uses cache data how it understand new inserted data? In my case new inserted data, directly in db, is being loaded. But directly updated data is not being loaded!!!! – A.v Aug 18 '16 at 22:47
0

Not so shockingly JPA has no prescient knowledge of other processes updating your database, how could it? You are the only person who knows about that and so have to use

em.refresh(obj)

to update the object, if you know that data has (possibly) changed.

Neil Stockton
  • 10,531
  • 3
  • 28
  • 27
  • But I think when I execute a query it should be run on db and get the result from db. – A.v Aug 19 '16 at 11:01
  • A query runs on the DB clearly, and the SQL issued will be in the log. BUT it will only show data that is appropriate for the transaction isolation. Only you know when exactly your objects were externally updated/added and whether txn isolation is a factor. Also the L1/L2 cache of JPA do not know about external processes, so they would need objects evicting if changed externally. – Neil Stockton Aug 19 '16 at 11:20
  • In situations like 2 app with db sharing mechanism jpa is nottsolution, because every time a query need to be executed a external change may have been occured, so the chache should be clear. Am I right? – A.v Aug 19 '16 at 18:25
  • 1
    As said, JPA has no mechanism for knowing of those external changes, just for persisting and querying of datastores. Providing a mechanism for detecting external changes is left to the application programmer, and make use of evict etc as required – Neil Stockton Aug 19 '16 at 18:48
0

The problem I was facing was that in spring before 4, which we had JpaTemplate for working with jpa entities, I passed EntityManager to the instances of JpaTemplate programmatically from an instance of EntityManagerFactory with no problem.

JpaTemplate itself would do any thing for flushing EntityManager and clearing cache. When I migrate to spring 4 I faced that JpaTemplate has been dropped so I have to work with EntityManager directly.

I get instance of EntityManager programmatically from an instance of EntityManagerFactory.

I have a EntityManagerProvider class which create an instance of EntityManager from an instance of EntityManagerFactory.

public class EntityManagerProvider {

    public static EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
        return entityManagerFactory.createEntityManager();
    }
}

I get entityManager instance like this:

<bean id="entityManager" class="com.tosan.novin.sipa.bo.da.jpa.EntityManagerFactoryProvider" factory-method="createEntityManager">
        <constructor-arg index="0" ref="entityManagerFactory"/>
</bean>

But I understand that if I want EntityManager to manage transactions and flushing the only way is use of @PersistenceContext for injecting EntityManager into my beans.

@PersistenceContext
protected EntityManager em;

I am a little confused yet with this manner but my problem solved with this approach.

A.v
  • 654
  • 4
  • 22