Question

I have the next two entities

Person:

@Entity
@Table(name = "person")
public class PersonDTO implements Serializable {

    private static final long serialVersionUID = -3859029259805663330L;

    @Id
    @Column(name = "person_id")
    @SequenceGenerator(name = "PERSON_GENERATOR", sequenceName = "seq_person_id")
    @GeneratedValue(generator = "PERSON_GENERATOR")
    private Long personId;

    @Column(name = "name")
    private String name;

    @OneToMany(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_id", updatable = false)
    @Cascade(value = { CascadeType.ALL, CascadeType.DELETE_ORPHAN })
    private List<PersonBookDTO> personBooks = new ArrayList<PersonBookDTO>();

    public Long getPersonId() {
    return personId;
    }

    public void setPersonId(final Long personId) {
    this.personId = personId;
    }

    public String getName() {
    return name;
    }

    public void setName(final String name) {
    this.name = name;
    }

    public List<PersonBookDTO> getPersonBooks() {
    return personBooks;
    }

    public void setPersonBooks(final List<PersonBookDTO> personBooks) {
    this.personBooks = personBooks;
    }

    /**
     * @see java.lang.Object#equals(Object)
     */
    @Override
    public boolean equals(final Object object) {
    if (!(object instanceof PersonDTO)) {
        return false;
    }
    PersonDTO rhs = (PersonDTO) object;
    return new EqualsBuilder().appendSuper(super.equals(object))
        .append(this.name, rhs.name).isEquals();
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
    return new HashCodeBuilder(1636021877, -141724713)
        .appendSuper(super.hashCode())
        .append(this.name).toHashCode();
    }
}

Person book:

@Entity
@Table(name = "person_book")
@NamedQueries({
    @NamedQuery(name = "PersonBookDTO.getBooksByPersonIdList", query = "from PersonBookDTO s where s.person.personId in(:personIdList) and s.disabled=false")
})
public class PersonBookDTO implements Serializable {
    private static final long serialVersionUID = -6382678873261874993L;

    @Id
    @Column(name = "person_book_id")
    @SequenceGenerator(name = "PERSON_BOOK_GENERATOR", sequenceName = "seq_person_book_id")
    @GeneratedValue(generator = "PERSON_BOOK_GENERATOR")
    private Long personBookId;

    @Column(name = "name")
    private String name;

    @Column(name = "disabled")
    private boolean disabled;

    @ManyToOne()
    @JoinColumn(name = "person_id")
    private PersonDTO person;

    public Long getPersonBookId() {
        return personBookId;
    }

    public void setPersonBookId(Long personBookId) {
        this.personBookId = personBookId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isDisabled() {
        return disabled;
    }

    public void setDisabled(boolean disabled) {
        this.disabled = disabled;
    }

    public PersonDTO getPerson() {
        return person;
    }

    public void setPerson(PersonDTO person) {
        this.person = person;
    }

    /**
     * @see java.lang.Object#equals(Object)
     */
    public boolean equals(Object object) {
        if (!(object instanceof PersonBookDTO)) {
            return false;
        }
        PersonBookDTO rhs = (PersonBookDTO) object;
        return new EqualsBuilder().appendSuper(super.equals(object)).append(this.disabled, rhs.disabled).append(this.personBookId, rhs.personBookId).append(this.name, rhs.name).append(this.person, rhs.person).isEquals();
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    public int hashCode() {
        return new HashCodeBuilder(213186089, -1592457573).appendSuper(super.hashCode()).append(this.disabled).append(this.personBookId).append(this.name).append(this.person).toHashCode();
    }
}

I've enabled hibernate 2nd level cache for this entities:

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>
<property name="net.sf.ehcache.configurationResourceName">/ehcache.xml</property>
...
<class-cache usage="read-write" class="com.test.dao.dto.PersonDTO"/>
<class-cache usage="read-write" class="com.test.dao.dto.PersonBookDTO"/>

Default cache from ehcache.xml:

<defaultCache 
    maxElementsInMemory="100000" 
    eternal="false"
    timeToIdleSeconds="86400" 
    timeToLiveSeconds="86400" 
    overflowToDisk="false"
    memoryStoreEvictionPolicy="LRU" 
    statistics="false"
>

Now I call the next test method in loop several times and in several threads: (personIdList is a List and was filled previously)

txManager.startTransaction();
Query query = getSession().getNamedQuery("PersonBookDTO.getBooksByPersonIdList");
query.setParameterList("personIdList", personIdList);
List<PersonBookDTO> =  query.list();
txManager.commitTransaction();
txManager.closeTransaction();

When I collected hibernate 2nd level cache statistis I've seen that only PersonDTO was taken from cache during the loop.

name: com.test.dao.dto.PersonDTO
count: 13
hit: 4
miss: 4
put: 13
size: 35389

and PersonBookDTO was only written

name: com.test.dao.dto.PersonBookDTO 
count: 29
hit: 0
miss: 0
put: 29
size: 38194

I've enabled TRACE level for ehCache. Here's a part of log:

TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8348946
TRACE [ReadWriteCache] Cached: com.test.dao.dto.PersonBookDTO#8348946
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#70276
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#79271
TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8376615
TRACE [ReadWriteCache] Item was already cached: com.test.dao.dto.PersonBookDTO#8376615
TRACE [ReadWriteCache] Cache hit: com.test.dao.dto.PersonDTO#63179
TRACE [ReadWriteCache] Caching: com.test.dao.dto.PersonBookDTO#8315141
TRACE [ReadWriteCache] Item was already cached: com.test.dao.dto.PersonBookDTO#8315141

Maybe someone can explain this behavoir. Thanks!

UPDATE: this reproduces with all queries which returns Lists of DTOs. session.read(PersonBookDTO) reads from cache normally.

Was it helpful?

Solution

Results of explicit query are fetched from the second level cache only when query cache is turned on and enabled for that query (by setting appropriate query hints). So, if you want to cache results of the query, you need to enable query cache.

If you want to retrieve entity data from the second level cache, but don't want to retrieve query result as a whole from the query cache, you can run a query for ids and then fetch entities with those ids manually.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top