0

I'm using eclipselink together with a Coherence distributed cache and a relational database (Toplink Grid - Grid cache configuration). Right now, I'm trying to perform a cache warm-up as efficiently as possible, reducing the number of future connections to the database.

I have a very simple data model: a parent entity (Person) with a one-directional One-To-Many relationship to the childs' entity (MagicCard)

@Entity
@Customizer(GridCacheCustomizer.class)
public class Person implements Serializable {
    @Id
    private int Id;

    @Version
    protected int version;

    private String surname;
    private String name;

    @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY , orphanRemoval=true )
    @CascadeOnDelete 
    @JoinColumn(name="person_id_ref")
    private List<MagicCard> cardList;
}

@Entity
@Customizer(GridCacheCustomizer.class)
public class MagicCard implements Serializable {

    @Id
    private int Id;

    private String descr;

    @Version
    protected int version;
}

In order to perform the cache warm-up, I'm doing a query using batch fetch. This way, I avoid the execution of N+1 database selects.

Query q = em.createQuery("select p from Person p"); 
q.setHint(QueryHints.BATCH, "p.cardList");
q.setHint(QueryHints.BATCH_TYPE, "IN");
q.setHint(QueryHints.LOAD_GROUP_ATTRIBUTE, "cardList"); 
List<Person> people = (List<Person>) q.getResultList();

which translates in runtime into:

[EL Fine]: sql: Connection(1099217286)--SELECT ID, NAME, SURNAME, VERSION FROM PERSON
[EL Fine]: sql: Connection(1099217286)--SELECT ID, DESCR, VERSION, person_id_ref FROM MAGICCARD WHERE (person_id_ref IN (?,?,?,?))
bind => [1, 2, 3, 4]

This search seems to be filling the Coherence caches for both entities correctly. The following log is from an example with 4 people (with 4,3,1 and 0 cards, respectively):

[EL Fine]: cache: Coherence(Person)::Get: [1, 2, 3, 4] result size: 4
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 1 value: entities.Person hashcode: 558082331
[EL Fine]: cache: Coherence(MagicCard)::Get: [3, 1, 2, 4, 5, 6, 7, 8] result size: 8
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 3 value: entities.MagicCard hashcode: 321885278
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 1 value: entities.MagicCard hashcode: 1206609130
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 2 value: entities.MagicCard hashcode: 1405610448
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 4 value: entities.MagicCard hashcode: 948640159
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 5 value: entities.MagicCard hashcode: 2122449463
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 6 value: entities.MagicCard hashcode: 714661629
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 7 value: entities.MagicCard hashcode: 905115332
[EL Fine]: cache: Coherence(MagicCard)::ConditionalPut: 8 value: entities.MagicCard hashcode: 127827822
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 2 value: entities.Person hashcode: 1268451305
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 3 value: entities.Person hashcode: 1535800224
[EL Fine]: cache: Coherence(Person)::ConditionalPut: 4 value: entities.Person hashcode: 164901111

*****************
cache : class com.tangosol.coherence.component.util.SafeNamedCache -- Person
.------- cache Person size 4
| KEY : 1 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 3 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 4 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
| KEY : 2 - VALUE TYPE : oracle.eclipselink.coherence.integrated.cache.wrappers.entities.Person_Wrapper
'--------------------

cache : class com.tangosol.coherence.component.util.SafeNamedCache -- MagicCard
.------- cache MagicCard size 8
| KEY : 1 - VALUE TYPE : Entities.MagicCard
| KEY : 7 - VALUE TYPE : Entities.MagicCard
| KEY : 3 - VALUE TYPE : Entities.MagicCard
| KEY : 5 - VALUE TYPE : Entities.MagicCard
| KEY : 4 - VALUE TYPE : Entities.MagicCard
| KEY : 6 - VALUE TYPE : Entities.MagicCard
| KEY : 2 - VALUE TYPE : Entities.MagicCard
| KEY : 8 - VALUE TYPE : Entities.MagicCard
'--------------------
*****************

Next, I try to find (using an EntityManager) a specific person, or a specific card

System.err.println("*** FINDING PERSON WITH ID=1 ***");
Person p = em1.find(Person.class, id);
System.out.println("[PERSON] " + p.toString());

and a cache search is successfully performed, as expected:

*** FINDING PERSON WITH ID=1 ***
[EL Fine]: cache: Coherence(Person)::Get: 1 result: entities.Person hashcode: 2132249404
[PERSON] Person [Id=1, name=x, surname=y]

however, when I try to find the cards of a person, eclipselink needs to perform an additional database select (I thought I'd avoid these with batch fetching(?)):

System.err.println("*** FINDING CARDS FROM PERSON WITH ID=1 ***");
Person p = em1.find(Person.class, id);
List<MagicCard> cards = p.getMagicCardList();
System.out.println(cards.size() + " cards found:\n");

---

[EL Fine]: cache: Coherence(Person)::Get: 1 result: entities.Person hashcode: 138084761
[EL Fine]: sql: Connection(278533322)--SELECT ID, DESCR, VERSION FROM MAGICCARD WHERE (person_id_ref = ?)
    bind => [1]
[EL Fine]: cache: Coherence(MagicCard)::Get: [3, 1, 2, 4] result size: 4
4 cards found

I was expecting it to get the list of cards from the coherence cache, and not from the database, since I had previously filled the former with everyone's cards. The only way I could get it to work as I desire was to change the @OneToMany FetchType to EAGER, but I'd like to avoid this change, since it has a negative impact in another part of my system.

Weren't the batch and load hints supposed to initialize the childs in the parent object? Or am I doing something wrong? Is there any other/better way of achieving this?

Thanks in advance

A3oN95
  • 11
  • 3
  • By using the batch fetch, you are ensuring that all needed MagicCard exist in the coherence cache, but I don't think coherence caches object relationships. Instead, a TopLink wrapper is used to fetch them - in the case of a OneToMany, this means querying. Since this type of query isn't based on a primary key, it has to go to the database as you've seen. It then fetches the data from the coherence cache rather than build the entities. – Chris Sep 26 '14 at 14:33
  • Thanks for the response. I know that the relationships are fetched by Toplink/EL. However, the elements in the Person cache are wrapped results, and not "simple" (POJO) Person objects. Therefore, they do (should?) contain the needed relationship information.If that data can't be retrieved from the coherence cache alone, how does that suddenly become possible simply by changing the FetchType to EAGER? – A3oN95 Sep 26 '14 at 15:45

0 Answers0