[真正的问题标记为粗体向下。以下是对我的情况的尽可能简短的解释]
我有以下JPA实体:
@Entity Genre{
private String name;
@OneToMany(mappedBy = "genre", cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Collection<Novel> novels;
}
@Entity
class Novel{
@ManyToOne(cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Genre genre;
private String titleUnique;
@OneToMany(mappedBy="novel", cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Collection<NovelEdition> editions;
}
@Entity
class NovelEdition{
private String publisherNameUnique;
private String year;
@ManyToOne(optional=false, cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Novel novel;
@ManyToOne(optional=false, cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Catalog appearsInCatalog;
}
@Entity
class Catalog{
private String name;
@OneToMany(mappedBy = "appearsInCatalog", cascade = {CascadeType.MERGE, CascadeType.PERSIST})
private Collection<NovelEdition> novelsInCatalog;
}
这个想法是拥有几个 Novels ,属于特定的类型,其中可以存在多个版本(不同的出版商,年份等)。为了简洁起见, NovelEdition 可以属于just 一个目录,就是这样一个由这样的文本文件代表的目录:
Catalog: Name Of Catalog 1
-----------------------
"Title of Novel 1", "Genre1 name","Publisher1 Name", 2009
"Title of Novel 2", "Genre1 name","Pulisher2 Name", 2010
.....
Catalog: Name Of Catalog 2
-----------------------
"Title of Novel 1", "Genre1 name","Publisher2 Name", 2011
"Title of Novel 2", "Genre1 name","Pulisher1 Name", 2011
.....
每个实体都使用Transaction Scoped EntityManager关联一个充当DAO的无状态EJB。例如:
@Stateless
public class NovelDAO extends AbstractDAO<Novel> {
@PersistenceContext(unitName = "XXX")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public NovelDAO() {
super(Novel.class);
}
//NovelDAO Specific methods
}
我感兴趣的是解析目录文件并构建相应的实体(我通常一次读取整批目录)。
作为解析字符串驱动的过程,我不想重复像 novelDAO.getByName(“Novel of Novel 1”)之类的操作,所以我想要集中使用缓存String-Identifier-&gt; Entity对象类型的映射。
目前我使用3个对象: 1)文件解析器,它执行以下操作:
final CatalogBuilder catalogBuilder = //JNDI Lookup
//for each file:
String catalogName = parseCatalogName(file);
catalogBuilder.setCatalogName(catalogName);
//For each novel edition
String title= parseNovelTitle();
String genre= parseGenre();
...
catalogBuilder.addNovelEdition(title, genre, publisher, year);
//End foreach
catalogBuilder.build();
2)CatalogBuilder是一个有状态EJB,它使用Cache并在每次解析新目录文件时重新初始化,并在目录持久化后被“删除”。
@Stateful
public class CatalogBuilder {
@PersistenceContext(unitName = "XXX", type = PersistenceContextType.EXTENDED)
private EntityManager em;
@EJB
private Cache cache;
private Catalog catalog;
@PostConstruct
public void initialize() {
catalog = new Catalog();
catalog.setNovelsInCatalog(new ArrayList<NovelEdition>());
}
public void addNovelEdition(String title, String genreStr, String publisher, String year){
Genre genre = cache.findGenreCreateIfAbsent(genreStr);//**
Novel novel = cache.findNovelCreateIfAbsent(title, genre);//**
NovelEdition novEd = new NovelEdition();
novEd.setNovel(novel);
//novEd.set publisher year catalog
catalog.getNovelsInCatalog().add();
}
public void setCatalogName(String name) {
catalog.setName(name);
}
@Remove
public void build(){
em.merge(catalog);
}
}
3)最后,有问题的bean:Cache 。对于CatalogBuilder,我使用了一个EXTENDED持久化上下文(我需要它作为Parser执行几个成功的事务)和一个有状态EJB; 但在这种情况下,我不确定我需要什么。实际上,缓存:
我现在拥有的是:
@Stateful
public class Cache {
@PersistenceContext(unitName = "XXX", type = PersistenceContextType.EXTENDED)
private EntityManager em;
@EJB
private sessionbean.GenreDAO genreDAO;
//DAOs for other cached entities
Map<String, Genre> genreName2Object=new TreeMap<String, Genre>();
@PostConstruct
public void initialize(){
for (Genre g: genreDAO.findAll()) {
genreName2Object.put(g.getName(), em.merge(g));
}
}
public Genre findGenreCreateIfAbsent(String genreName){
if (genreName2Object.containsKey(genreName){
return genreName2Object.get(genreName);
}
Genre g = new Genre();
g.setName();
g.setNovels(new ArrayList<Novel>());
genreDAO.persist(t);
genreName2Object.put(t.getIdentifier(), em.merge(t));
return t;
}
}
但老实说我找不到同时满足这3点的解决方案。例如,使用另一个具有扩展持久化上下文的有状态bean 将适用于第一个已解析的文件,但我有 不知道第二个文件应该发生什么..确实对于第一个文件,PC将被创建并从 CatalogBuilder 传播到 Cache ,然后将使用相同的PC 。但是在build()返回之后, CatalogBuilder的PC应该(我猜)在连续解析过程中被删除并重新创建,尽管Cache的PC应该保持“活着”:在这种情况下不应该抛出异常吗?另一个问题是 Cache bean被钝化时该怎么办。目前我得到例外:
"passivateEJB(), Exception caught ->
java.io.IOException: java.io.IOException
at com.sun.ejb.base.io.IOUtils.serializeObject(IOUtils.java:101)
at com.sun.ejb.containers.util.cache.LruSessionCache.saveStateToStore(LruSessionCache.java:501)"
因此,我不知道如何实现我的缓存。你会如何解决这个问题?
答案 0 :(得分:0)
EclipseLink配置:
您可以在配置文件中为所有entites指定属性。
<property name="eclipselink.cache.shared.default" value="true"/>
在具有@Cache
注释的实体级别,指定不同的属性。
常规JPA配置:
在实体级别,使用@Cacheable
注释,value
属性为true
。
按CacheRetrieveMode
指定检索模式,属性USE
启用其他BYPASS
。
entityManager.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE);
使用CacheStoreMode
,BYPASS
或USE
属性REFRESH
在缓存中配置存储空间。
entityManager.setProperty("javax.persistence.cache.storeMode",CacheStoreMode.REFRESH);
Cache
接口表示共享缓存。要删除所有或某些缓存实体,可以调用其中一个evict方法。您可以从EntityManagerFactory
获取缓存接口的参考。