I have two entities Book and Author. Book has a collection of authors. I am using second level cache to keep the Book entity with its Authors. When debugging I can see there is putForExternalRead
is happening for Book instance and each author in collection. But when I am calling find(Book.class, ISBN)
method again it is using cache just for book while the collection of authors is retrieved each time from database. Each time collection of authors are put in second level cache. Please let me know if there is some where I need to change cache access strategy for collection. I am using Jboss 6.0 Infinispan 5. and postgres 9 DBMS.
Here is my code
package bookentity.ejb;
/* * To change this template, choose Tools | Templates * and open the template in the editor. */
import java.io.Serializable;
import java.util.ArrayList;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.ManyToMany;
import javax.persistence.JoinTable;
//import javax.persistence.JoinColumns;
import javax.persistence.JoinColumn;
import java.util.Collection;
import java.util.List;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
//import javax.persistence.inv
import javax.persistence.OneToMany;
@Entity
@Cacheable
@Table(name = "BOOK")
@NamedQueries({@NamedQuery(name="findBookByAuthorName",query="SELECT b FROM Book b, Author a WHERE a.authorName=:authorName AND b = SOME(SELECT x FROM a.books x)"),
@NamedQuery(name="findBookByTitle",query="SELECT b FROM Book b WHERE b.title=:bTitle")})
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private int ISBN;
private String title;
private String description;
private Author author;
// @ManyToMany(fetch=FetchType.LAZY)
@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="BOOK_AUTHOR", joinColumns=@JoinColumn(name="BOOK_ID"),
inverseJoinColumns=@JoinColumn(name="AUTHOR_ID"))
private Collection<Author> authors;
//@OneToMany(fetch=FetchType.EAGER, mappedBy="bookEntity")
@OneToMany(fetch=FetchType.LAZY, mappedBy="bookEntity")
public Collection<Review> reviews;
public Book() {
authors = new ArrayList<Author>();
reviews = new ArrayList<Review>();
}
public int getISBN() {
return ISBN;
}
public void setISBN(int ISBN) {
this.ISBN = ISBN;
}
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getDescription(){
return description;
}
public void setDescription(String description){
this.description = description;
}
public void addReview(Review review){
if(!getReviews().contains(review)){
getReviews().add(review);
if(review.getBookEntity()!=null){
review.getBookEntity().getReviews().remove(this);
}
review.setBookEntity(this);
}
}
public void addAuthor(Author author){
if (!getAuthors().contains(author)){
getAuthors().add(author);
}
if(!author.getBooks().contains(this)){
author.getBooks().add(this);
}
}
public Collection<Review> getReviews(){
return reviews;
}
public Collection<Author> getAuthors(){
return authors;
}
void setAuhorId(int authorID) {
}
}
Here is the code for Author Entity
package bookentity.ejb;
import java.io.Serializable;
import java.util.ArrayList;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
@Entity
@Cacheable
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private int author_id;
String authorName;
String authAddress;
@ManyToMany(mappedBy = "authors")
private Collection<Book> books;
public Author() {
books = new ArrayList<Book>();
}
public void setAuthor_id(int author_id) {
this.author_id = author_id;
}
public int getAuthorId() {
return this.author_id;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getAuthorName() {
return authorName;
}
public String getAuthorAddress(){
return this.authAddress;
}
public void setAuthorAddress(String authAddress){
this.authAddress = authAddress;
}
public Collection<Book> getBooks() {
return books;
}
public void addBook(Book book){
if(!getBooks().contains(book)) {
getBooks().add(book);
//book.getAuthors().add(this);
}
if (!book.getAuthors().contains(this)){
book.getAuthors().add(this);
}
}
}
Here is the persistence.xml file
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
<persistence-unit name="BookAuthorApp3-ejbPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/PostgresDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.session_factory_name" value="SessionFactories/infinispan1" />
<property name="javax.persistence.sharedCache.mode" value="ALL" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.cacheable" value="true" />
<property name="hibernate.cache.use_structured_entries" value="true" />
<property name="hibernate.cache.infinispan.collection.cfg" value="entity" />
<property name="hibernate.cache.infinispan.bookentity.ej.Book.cfg" value="Books"/>
<property name="hibernate.cache.infinispan.bookentity.ej.Book.authors.cfg" value="Authors"/>
<property name="hibernate.cache.infinispan.statistics" value="true"/>
<property name="hibernate.generate_statistics" value="true" />
<property name="hibernate.cache.region_prefix" value="infinispan" />
<property name="hibernate.cache.infinispan.entity.cfg" value="entity" />
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.JndiInfinispanRegionFactory" />
<property name="hibernate.cache.infinispan.cachemanager" value="java:CacheManager/entity" />
</properties>
Here is the infinispan-configs.xml file
<infinispan-config name="hibernate" jndi-name="java:CacheManager/entity">
<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:5.0 http://www.infinispan.org/schemas/infinispan-config-5.0.xsd"
xmlns="urn:infinispan:config:5.0">
<global>
<transport clusterName="${jboss.partition.name:DefaultPartition}-Hibernate" distributedSyncTimeout="17500">
<properties>
<property name="stack" value="${jboss.default.jgroups.stack:udp}"/>
</properties>
</transport>
<globalJmxStatistics enabled="true"/>
<shutdown hookBehavior="DONT_REGISTER"/>
</global>
<default>
<jmxStatistics enabled="false"/>
<!--transaction transactionManagerLookupClass="org.infinispan.transaction.lookup.JBossTransactionManagerLookup"/-->
</default>
<namedCache name="entity">
<clustering mode="invalidation">
<stateRetrieval fetchInMemoryState="false" timeout="20000"/>
<sync replTimeout="20000"/>
</clustering>
<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000"
lockAcquisitionTimeout="15000" useLockStriping="false" />
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
<expiration lifespan = "-1" maxIdle="-1"/>
<lazyDeserialization enabled="true"/>
</namedCache>